I need a subroutine for my program written in scheme that takes an integer, say 34109, and puts it into a list with elements 3, 4, 1, 0, 9. The integer can be any length. Does anyone have a trick for this? I've thought about using modulo for every place, but I don't think it should be that complicated.
问题:
回答1:
The simplest way I can think of, is by using arithmetic operations and a named let
for implementing a tail-recursion:
(define (number->list num)
(let loop ((num num)
(acc '()))
(if (< num 10)
(cons num acc)
(loop (quotient num 10)
(cons (remainder num 10) acc)))))
Alternatively, you can solve this problem using string operations:
(define char-zero (char->integer #\0))
(define (char->digit c)
(- (char->integer c) char-zero))
(define (number->list num)
(map char->digit
(string->list (number->string num))))
This can be compressed into a single function, but I believe it's easier to understand if we split the problem in subparts as above.
(define (number->list num)
(map (lambda (c) (- (char->integer c) (char->integer #\0)))
(string->list
(number->string num))))
Anyway, the results are as expected:
(number->list 34109)
> '(3 4 1 0 9)
回答2:
Something like this:
(define (num2list-helper num lst)
(cond ((< num 10) (cons num lst))
(else (num2list-helper (floor (/ num 10)) (cons (modulo num 10) lst)))))
(define (num2list num)
(num2list-helper num '()))
(num2list 1432)
As itsbruce commented you can hide helper function inside main one:
(define (num2list num)
(define (num2list-helper num lst)
(cond ((< num 10) (cons num lst))
(else (num2list-helper (floor (/ num 10)) (cons (modulo num 10) lst)))))
(num2list-helper num '()))
(num2list 1432)
to be continued...
回答3:
I'm not a fan of manual looping, so here's a solution based on unfold (load SRFI 1 and SRFI 26 first):
(define (digits n)
(unfold-right zero? (cut modulo <> 10) (cut quotient <> 10) n))
This returns an empty list for 0, though. If you want it to return (0)
instead, we add a special case:
(define (digits n)
(case n
((0) '(0))
(else (unfold-right zero? (cut modulo <> 10) (cut quotient <> 10) n))))
Of course, you can generalise this for other bases. Here, I implement this using optional arguments, so if you don't specify the base, it defaults to 10:
(define (digits n (base 10))
(case n
((0) '(0))
(else (unfold-right zero? (cut modulo <> base) (cut quotient <> base) n))))
Different Scheme implementations use different syntaxes for optional arguments; the above uses Racket-style (and/or SRFI 89-style) syntax.