Номер схемы к списку
Мне нужна подпрограмма для моей программы, написанная по схеме, которая принимает целое число, скажем 34109, и помещает его в список с элементами 3, 4, 1, 0, 9. Целое число может быть любой длины. У кого-нибудь есть хитрость для этого? Я думал об использовании по модулю для каждого места, но я не думаю, что это должно быть так сложно.
3 ответа
Самым простым способом, который я могу придумать, является использование арифметических операций и именованногоlet
для реализации хвостовой рекурсии:
(define (number->list num)
(let loop ((num num)
(acc '()))
(if (< num 10)
(cons num acc)
(loop (quotient num 10)
(cons (remainder num 10) acc)))))
Кроме того, вы можете решить эту проблему, используя строковые операции:
(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))))
Это можно сжать в одну функцию, но я считаю, что это легче понять, если мы разделим проблему на части, как описано выше.
(define (number->list num)
(map (lambda (c) (- (char->integer c) (char->integer #\0)))
(string->list
(number->string num))))
Во всяком случае, результаты, как и ожидалось:
(number->list 34109)
> '(3 4 1 0 9)
Что-то вроде этого:
(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)
Как отметил его Брюс, вы можете скрыть вспомогательную функцию внутри основной:
(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)
продолжение следует...
Я не фанат ручного зацикливания, поэтому вот решение, основанное на развертывании (сначала загрузите SRFI 1 и SRFI 26):
(define (digits n)
(unfold-right zero? (cut modulo <> 10) (cut quotient <> 10) n))
Это возвращает пустой список для 0, хотя. Если хочешь вернуть (0)
вместо этого мы добавляем особый случай:
(define (digits n)
(case n
((0) '(0))
(else (unfold-right zero? (cut modulo <> 10) (cut quotient <> 10) n))))
Конечно, вы можете обобщить это для других основ. Здесь я реализую это, используя необязательные аргументы, поэтому, если вы не укажете основание, по умолчанию будет 10:
(define (digits n (base 10))
(case n
((0) '(0))
(else (unfold-right zero? (cut modulo <> base) (cut quotient <> base) n))))
Различные реализации Схемы используют разные синтаксисы для необязательных аргументов; Выше используется синтаксис в стиле Racket (и / или в стиле SRFI 89).