How do I delete colons (:) in my lists? - scheme

I am starting to learn racket. There is a example which is about time and I need remove colons (:) from my list. For example;
11:30 -> 1130
I want to do it because I will putting them in order which is first, second, third and fourth.
P.S.: Sorry about my English.

(define L (list "22:30"))
(string-append (substring (first L) 0 2) (substring (first L) 3 5))
Output: "2230"

Try this:
(string-replace "11:30" ":" "")
If you need to do something with the digits, you can convert your string into a number or a list of digits. It goes like this:
;; convert a string into an integer
(define S (string->number (string-replace "11:30" ":" "")))
;; produce a list of digits from a given integer
(define (int->list n)
(cond [(zero? n) empty]
[else
(append (int->list (quotient n 10))
(list (remainder n 10)))]))
;; try it in REPL
> (int->list S)
'(1 1 3 0)

Related

In scheme, how do I determine if the characters in the lists I have are changing

In scheme, how do I determine if the characters in the lists I have are changing
(define (increasing-character-numbers? strings)
"Return true if number of characters are increasing"
(cond ((< (length strings) 2) #f)
(t (apply < (map string-length strings))))
;; or use an `and` for such kind of conditions:
(define (increasing-character-numbers? strings)
(and (< 1 (length strings)) (apply < (map strings-length strings))))
> (increasing-character-numbers? '("a" "aa" "aaa"))
#t
> (increasing-character-numbers? '("aaa" "a"))
#f
> (increasing-character-numbers? '("a" "a"))
#f
(map string-length strings)
determines the number of characters in each of the strings in the list strings.
The lisp magic is in (apply < char-nums-in-strings).
It takes the list of character numbers and adds in front of it the < function to ask whether they are in increasing order to each other from left to the right. If the number of characters stays equal between two neighbours - it will return already #f.
One can tolerate such cases by <=.
(apply <= '(1 2 2 3 3 3 4)) ;; => #t
(apply <= '(1 2 2 3 4 3))` ;;=> #f
changing characters
After changing your original question - I would answer to that:
(define (characters-changing? strings)
(and (< 1 (length strings)) (not (apply string=? strings))))

Idiomatic way to decode hex-formatted strings in Racket Scheme or other schemes

My input data is a hex-formatted string without restriction on the length. I need to process the bytes individually. As an example, for "AABBCCDDEEFF" I want to process AA, then BB, CC, DD, EE, FF.
Using Common Lisp, we can use LOOP:
(loop for (a b) on list do [processing])
In Racket Scheme, I wrote this solution:
(define (split-string str)
(let ((bit #t)
(char-1 null)
(char-2 null)
(result '()))
(for ((char str))
(if bit
(begin
(set! bit #f)
(set! char-1 char))
(begin
(set! bit #t)
(set! char-2 char)
(set! result (cons (~a char-1 char-2) result)))))
;; return
(reverse result)))
(split-string "AABBCCDDEEFF")
;; '("AA" "BB" "CC" "DD" "EE" "FF")
I feel like this is not idiomatic Racket or Scheme code. I wrote a second solution:
(define (split-string2 str)
(bytes->list (integer->integer-bytes (string->number str 16) 8 false)))
(split-string2 "AABBCCDDEEFF")
;; '(255 238 221 204 187 170 0 0)
What is the idiomatic way to perform this kind of operations in Racket Scheme and more generally in Lisp?
There are a bunch of ways of doing this in Racket (as opposed to Scheme more generally): the notions you want are sequences, streams and generators.
First of all a function to compute hex digits from characters (this may exist in Racket, but I was too lazy to find it, and this works):
(define (char->hex-digit c)
;; Turn a character into a hex digit
(cond [(char<=? #\0 c #\9)
(- (char->integer c) (char->integer #\0))]
[(char<=? #\A c #\F)
(+ 10 (- (char->integer c) (char->integer #\A)))]
[(char<=? #\a c #\f)
(+ 10 (- (char->integer c) (char->integer #\a)))]
[else
(error 'char->hex-digit "~A is not a hex character" c)]))
Now here is a simple-minded approach to turning a hex string into a list of bytes which works by creating two sequences from the string, one of which picks out the high and the other the low digit in each pair:
(define (hex-string->byte-list hs)
(for/list ([h (in-string hs 0 #f 2)]
[l (in-string hs 1 #f 2)])
(+ (* (char->hex-digit h) 16) (char->hex-digit l))))
Obviously depending on which variant of for you use you can construct different results.
Examples:
> (hex-string->byte-list "F00D")
'(240 13)
> (hex-string->byte-list "0102030405060708090a0b0C0D0F")
'(1 2 3 4 5 6 7 8 9 10 11 12 13 15)
> (hex-string->byte-list "01xa")
; char->hex-digit: x is not a hex character [,bt for context]
Another approach is to use in-slice:
(define (hex-string->byte-list hs)
(for/list ([hl (in-slice 2 (in-string hs))])
(+ (* (char->hex-digit (first hl)) 16) (char->hex-digit (second hl)))))
And there are lots of other ways of doing this, including creating your own sequence or stream types, so you could write (for/list ([b (in-hex-stream-bytes ...)]) b).
Note that the Common Lisp version would not work since the input is a string; in order to use the same approach you should first convert the string to a list of characters; secondly, you would need to add a by directive to advance over the list by cddr, i.e. skipping the already read b.
That would finally look like:
(loop
for (a b) on (coerce "AABBCCDDEEFF" 'list) by #'cddr
collect (parse-integer (coerce (vector a b) 'string)
:radix 16))
=> (170 187 204 221 238 255)
But, this is a bit wasteful, parse-integer admits :start and :end arguments, so you do not need to allocate any intermediate list or string (apart for the last collect; you could skip it too and just process the value directly):
(loop
with string = "AABBCCDDEEFF"
with size = (length string)
initially (assert (evenp size))
for start from 0 by 2
for end from 2 by 2 upto size
collect (parse-integer string :start start :end end :radix 16))
=> (170 187 204 221 238 255)
One of the idiomatic ways would be to use recursion (preserving the same functionality as your split-string) as follows:
(define (split-string-recur str)
(cond [(or (string=? str "") (string=? "" (substring str 1))) '()]
[else (cons (substring str 0 2) (split-string-recur (substring str 2)))]))
and a tail-recursive version:
(define (split-string-trecur str)
(define (split-string-recur str acc)
(cond [(or (string=? str "") (string=? "" (substring str 1))) acc]
[else (split-string-recur (substring str 2) (append acc (list (substring str 0 2))))]))
(split-string-recur str '()))
The for/list approach with in-slice on in-string sequence (mentioned here) is also an idiomatic approach.
Note that we can also use a small interface on strings like the following to make it more readable:
(module string-util typed/racket
(provide (all-defined-out))
(: empty-string? : (-> String Boolean))
(define (empty-string? s)
(string=? "" s))
(: string-first : (-> String String))
(define (string-first s)
(substring s 0 1))
(: string-last : (-> String String))
(define (string-last s)
(substring s (- (string-length s) 1) (string-length s)))
(: string-rest : (-> String String))
(define (string-rest s)
(substring s 1 (string-length s))))
(require 'string-util)
(define (split-string-recur str)
(cond [(or (empty-string? str) (empty-string? (string-rest str))) '()]
[else (cons (string-append (string-first str) (string-first (string-rest str)))
(split-string-recur (string-rest (string-rest str))))]))
CL-USER 2 > (defun split-string (string)
(loop for i from 0 below (length string) by 2
collect (subseq string i (+ i 2))))
SPLIT-STRING
CL-USER 3 > (split-string "AABBCCDDEEFF")
("AA" "BB" "CC" "DD" "EE" "FF")
CL-USER 4 > (mapcar (lambda (s) (parse-integer s :radix 16)) *)
(170 187 204 221 238 255)

Easy function to commatize a number in string in Racket

To add commas to a number in string, can there be a simple function for common situation use? I found one method but it seems very complex though comprehensive: https://rosettacode.org/wiki/Commatizing_numbers#Racket
I simply want to have a function which works as follows:
(addcommas 1234567890)
"1,234,567,890"
(It is slightly surprising that Racket, which has many high level functions, does not have a built-in function for this common requirement).
You can try with this:
(define (addcommas n)
(define (split n acc)
(if (< (abs n) 1000)
(cons n acc)
(let-values ([(quot rem) (quotient/remainder n 1000)])
(split quot (cons (abs rem) acc)))))
(apply ~a (split n '()) #:separator ","))
(addcommas -2332342390)
;; -> "-2,332,342,390"
If you want to format real numbers, since they have a binary representation, and the conversion can be imprecise, you have to add a precision parameter which specifies the number of digits after the point:
(define (addcommas-real n precision)
(let* ((int-part (exact-truncate n))
(float-part (exact-truncate (* (- n int-part) (expt 10 precision)))))
(~a (addcommas int-part) "." (abs float-part))))
(addcommas-real -2332342390.34 2)
;; -> "-2,332,342,390.34"
(addcommas-real -2332342390.34 5)
;; -> "-2,332,342,390.34000"

Tonumber function (tonumber ‘(one two three) --> 123

After the solution of how to spell a number in racket? (spellNum) ,now I am trying to write a function which is opposite of this function. i.e
(tonumber ‘(one two three) --> 123
so far I have written this working code
(define (symbol->digit n)
(case n
('zero 0)
('one 1)
('two 2)
('three 3)
('four 4)
('five 5)
('six 6)
('seven 7)
('eight 8)
('nine 9)
(else (error "unknown symbol:" n))))
(define (numlist n)
(map symbol->digit n))
(numlist '(one two three))
From numlist, I got '(1 2 3). But to there is some problem in the function below in which I want to convert list to number
(define (list->number l)
(set! multiplier (* 10 (lenght l)))
(for/list [(c l)]
(* multiplier c))
(set! multiplier (/ multiplier 10)))
(list->number '(1 2 3))
any help will be appreciated. I can't find documentation of all kind of loops online. at
http://docs.racket-lang.org/ts-reference/special-forms.html?q=loop#%28part._.Loops%29
I want to become familiar with Racket so I want to avoid builtin conversion functions. In list->number,I am trying to take digits one by one from list and then i want to multiply them with 10,100,1000 so on depending on the length of list. so that it can return a number. For example '(1 2 3) = 1*100+2*10+3*1
Here's the exact opposite of my previous solution, once again using tail recursion for the list->number procedure:
(define (symbol->digit n)
(case n
('zero 0)
('one 1)
('two 2)
('three 3)
('four 4)
('five 5)
('six 6)
('seven 7)
('eight 8)
('nine 9)
(else (error "unknown symbol:" n))))
(define (list->number lst)
(let loop ((acc 0) (lst lst))
(if (null? lst)
acc
(loop (+ (car lst) (* 10 acc)) (cdr lst)))))
(define (toNumber lst)
(list->number (map symbol->digit lst)))
It works as expected:
(toNumber '(four six seven))
=> 467
Just for fun, in Racket we can write a function like list->number using iteration and comprehensions. Even so, notice that we don't use set! anywhere, mutating state is the norm in a language like Python but in Scheme in general and Racket in particular we try to avoid modifying variables inside a loop - there are more elegant ways to express a solution:
(define (list->number lst)
(for/fold ([acc 0]) ([e lst])
(+ e (* 10 acc))))
(define (symbol->digit n)
(case n
('zero "0")
('one "1")
('two "2")
('three "3")
('four "4")
('five "5")
('six "6")
('seven "7")
('eight "8")
('nine "9")
(else (error "unknown symbol:" n))))
(define (symbols->number symb)
(string->number (string-join (map symbol->digit symb) "")))
(symbols->number '(one two three))
Lots of ways to skin a cat. Here is version that uses fold-left. Like Óscar's solution it uses math rather than chars and strings.
#!r6rs
(import (rnrs))
;; converts list with worded digits into
;; what number they represent.
;; (words->number '(one two zero)) ==> 120
(define (words->number lst)
(fold-left (lambda (acc x)
(+ x (* acc 10)))
0
(map symbol->digit lst)))
For a #!racket version just rename fold-left to foldl and switch the order of x and acc.

Why is this expression giving me a function body error?

(define (subtract-1 n)
(string-append "Number is: " (number->string n))
(cond
[(= n 0) "All done!"]
[else (subtract-1(- n 1))]))
I keep getting the error: define: expected only one expression for the function body, but found 1 extra part. I'm not understanding why I'm getting this.
NOTE TO SELF: When using DrRacket, Setting the language to BSL may make Racket commands error at compile time.
The language you're using (BSL) only allows a single expression inside the body of a procedure, if there's more than one expression, you need to pack them inside a begin.
Also notice that the string-append line is doing nothing, you should print it or accumulate it. Here's a possible solution with my recommendations in place:
(define (subtract-1 n)
(begin
(display (string-append "Number is: " (number->string n) "\n"))
(cond
[(= n 0) "All done!"]
[else (subtract-1 (- n 1))])))
Even better, use the printf procedure for simplicity's sake:
(define (subtract-1 n)
(begin
(printf "~a ~s~n" "Number is:" n)
(cond
[(= n 0) "All done!"]
[else (subtract-1 (- n 1))])))
Either way a sample execution looks like this:
(subtract-1 3)
=> Number is: 3
=> Number is: 2
=> Number is: 1
=> Number is: 0
=> "All done!"
Racket documentation (Sequencing) seems to suggest that you might need to use a begin expression for this to work, or it might be the missing space in (subtract-1(- n 1)) between the function name and the parameter.
Also, you probably want to output the result of
string-append as it's not really doing anything as it is. Example to cover off all these points:
(define (subtract-1 n)
(begin
(write (string-append "Number is: " (number->string n)))
(cond
[(= n 0) "All done!"]
[else (subtract-1 (- n 1))])))

Resources