在 Scheme 中增加一个字母字符串
Incrementing an alphabetic string in Scheme
我正在尝试在 Scheme 中以编程方式递增纯字母字符串。
像这样"MA",然后"MB",当它达到"MZ"时,它应该变成"MAA"等等,直到"MZZ"然后它应该变成 "MAAA" 所以 on.The "M" 需要添加为我正在做的那种工作的前缀。
我看了这个问题:Incrementing alphabets 这正是我想要的。
但是,我完全不知道从哪里开始。对于初学者,我什至不确定如何在方案中处理 ASCII。我并不期待完整的代码,但如果我能得到一些提示,我将不胜感激。
这是我的实现。注意需要加载SRFI 1,它提供了unfold-right
:
(define letters "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
(define (number->letters num)
(unfold-right negative?
(lambda (i) (string-ref letters (remainder i 26)))
(lambda (i) (- (quotient i 26) 1))
num))
(define (number->tag num)
(list->string (cons #\M (number->letters num))))
示例:
> (number->tag 0)
"MA"
> (number->tag 18277)
"MZZZ"
> (number->tag 18278)
"MAAAA"
OP 要求解释代码的作用。因此,了解 OP 已经理解 算法 (因为他们已经链接到它),基本上剩下的就是展开操作。
折叠和展开的解释有点冗长,我不想通过解释它们来破坏这个 post,但是可以 "expand" 展开进入等效循环(使用与 unfold-right
的 SRFI 1 reference implementation 相同的变量名称)来表达正在发生的事情:
(define (number->letters num)
(let lp ((seed num) (ans '()))
(if (negative? seed)
ans
(lp (- (quotient seed 26) 1)
(cons (string-ref letters (remainder seed 26)) ans)))))
基本上,它构建一个列表,从右到左,每次迭代使用 (string-ref letters (remainder seed 26))
(其中 seed
在初始迭代中是 num
)。 seed
的值然后在下一次迭代中更新为 (- (quotient seed 26) 1)
。当 (negative? seed)
为真时,列表停止。
然后您可能会问为什么要使用展开而不是循环。基本上,在函数式编程中,当 "concept" 可以用更高级别的术语(例如,for-each、map、filter、fold 或 unfold)表示时,使用这些术语可以帮助其他程序员理解代码的作用。在函数式编程上下文中,它有点像 "design patterns"(在面向对象编程中常用)。 :-)
我正在尝试在 Scheme 中以编程方式递增纯字母字符串。
像这样"MA",然后"MB",当它达到"MZ"时,它应该变成"MAA"等等,直到"MZZ"然后它应该变成 "MAAA" 所以 on.The "M" 需要添加为我正在做的那种工作的前缀。
我看了这个问题:Incrementing alphabets 这正是我想要的。
但是,我完全不知道从哪里开始。对于初学者,我什至不确定如何在方案中处理 ASCII。我并不期待完整的代码,但如果我能得到一些提示,我将不胜感激。
这是我的实现。注意需要加载SRFI 1,它提供了unfold-right
:
(define letters "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
(define (number->letters num)
(unfold-right negative?
(lambda (i) (string-ref letters (remainder i 26)))
(lambda (i) (- (quotient i 26) 1))
num))
(define (number->tag num)
(list->string (cons #\M (number->letters num))))
示例:
> (number->tag 0)
"MA"
> (number->tag 18277)
"MZZZ"
> (number->tag 18278)
"MAAAA"
OP 要求解释代码的作用。因此,了解 OP 已经理解 算法 (因为他们已经链接到它),基本上剩下的就是展开操作。
折叠和展开的解释有点冗长,我不想通过解释它们来破坏这个 post,但是可以 "expand" 展开进入等效循环(使用与 unfold-right
的 SRFI 1 reference implementation 相同的变量名称)来表达正在发生的事情:
(define (number->letters num)
(let lp ((seed num) (ans '()))
(if (negative? seed)
ans
(lp (- (quotient seed 26) 1)
(cons (string-ref letters (remainder seed 26)) ans)))))
基本上,它构建一个列表,从右到左,每次迭代使用 (string-ref letters (remainder seed 26))
(其中 seed
在初始迭代中是 num
)。 seed
的值然后在下一次迭代中更新为 (- (quotient seed 26) 1)
。当 (negative? seed)
为真时,列表停止。
然后您可能会问为什么要使用展开而不是循环。基本上,在函数式编程中,当 "concept" 可以用更高级别的术语(例如,for-each、map、filter、fold 或 unfold)表示时,使用这些术语可以帮助其他程序员理解代码的作用。在函数式编程上下文中,它有点像 "design patterns"(在面向对象编程中常用)。 :-)