Reputation: 495
Im trying to create a function which will take a integer argument and returns those integers with their position within the number spelled out. For example.
(number 2135567667)
'(2 billion 135 million 567 thousand 667)
I figured I would split the integer into groups of 3's from right to left with quotient and remainder. And use the sentence
'(thousand million billion trillion quadrillion)
To interject the appropriate symbol within the output sentence. However there are cases where entire groups will be zeros such as:
(number 1000000)
'(1 million)
or
(1000000001)
1 billion 1
Is there a better way to go about the problem? Or how can I ommit a group and its name if it is zero?
(define 1to19 '(one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen))
(define multiple '(twenty thirty forty fifty sixty seventy eighty ninety))
(let loop ((n n) (units thousands) (acc '()))
(cond
((= n 0) acc)
((< 0 n 20) (cons (list-ref 1to19 (- n 1)) acc))
((< n 100) (cons (list-ref multiples (- (quotient n 10) 2))
(loop (remainder n 10) '() acc)))
((< n 1000) (loop (quotient n 100)
'()
(cons 'hundred (loop (remainder n 100) '() res))))
Upvotes: 0
Views: 172
Reputation: 2789
One approach you can take to construct the list is by adding in units while splitting the number into groups. For example, in Racket you can have:
(define (number n)
(define units '(thousand million billion trillion quadrillion))
(define (nsplit n units acc lst)
(define q (quotient n 1000))
(define r (remainder n 1000))
(if (zero? n) lst
(cond [(zero? acc)
(if (zero? r)
(nsplit q units (add1 acc) lst)
(nsplit q units (add1 acc) (cons r lst)))]
[(zero? r)
(nsplit q (cdr units) acc lst)]
[else
(nsplit q (cdr units) acc (cons r (cons (car units) lst)))])))
(nsplit n units 0 empty))
and then:
> (number 2135567667)
'(2 billion 135 million 567 thousand 667)
> (number 1000000)
'(1 million)
> (number 1000000001)
'(1 billion 1)
Upvotes: 1