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

2019-03-04 17:22发布

问题:

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

回答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))))


回答2:

(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))


回答3:

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.



标签: scheme racket