我使用SBCL和来自quicklisp的iterate
包解决了Project Euler的第8个问题。在我的代码中,我定义了一个函数,将一个数字转换为它的数字列表。这是源代码:
(defun number-to-list (n)
(iter (for c in-string (write-to-string n)) (collect (digit-char-p c))))
collect
和iter
中的loop
子句会列出值列表。是否有可能生成一个向量(一维数组)?
我唯一的选择是将number-to-list
生成的列表转换为向量吗?因为这似乎效率低下(虽然可能 效率低下)
答案 0 :(得分:2)
通常有一个大问题:结果向量有多大?最好先知道,然后我们可以用正确的大小分配矢量一次。否则我们会找到解决这个问题的方法:使用可调整大小的向量,先分配一个列表并稍后复制到结果向量中,使用填充指针分配一个更大的向量,...
如果你有一个序列,那么可以使用Common Lisp函数MAP
:如果源对象是一个向量,这里是一个字符串,它的长度很便宜。
CL-USER 1 > (map 'vector
#'digit-char-p
(write-to-string 5837457324534))
#(5 8 3 7 4 5 7 3 2 4 5 3 4)
您可以使用ITERATE
并收集矢量:
FOO 32 > (defun number-to-vector (n)
(iter (for c in-string (write-to-string n))
(collect (digit-char-p c) result-type vector)))
NUMBER-TO-VECTOR
FOO 33 > (number-to-vector 8573475934)
#(8 5 7 3 4 7 5 9 3 4)
如果查看宏扩展,它实际上会收集到一个列表中,然后调用COERCE
来创建向量。所以:没有效率的胜利。
请注意,这是ITERATE
比LOOP
更强大的另一个示例:标准LOOP
无法直接从 collect 返回向量。
答案 1 :(得分:2)
建议的解决方案是正确和优雅的,但它们首先创建一个列表,或者用字符串转换数字。我想建议从整数到数组的直接转换,而不首先转换列表或字符串中的数字:
JobDispatcher
使用给出整数n的十进制数字的公式来解决分配正确维度的数组的问题:⌊log 10 n⌋+ 1。
答案 2 :(得分:1)
也许不是你问题的直接答案,但这里是我经常使用的num-to-list和list-to-num函数。
(defun num-to-list-helper (n liste)
(cond ((< n 1) liste)
(t (num-to-list-helper (truncate (/ n 10)) (cons (rem n 10) liste))))))
(defun num-to-list (n)
(num-to-list-helper n nil))
(defun list-to-num-helper (liste n)
(if (null liste)
n
(list-to-num-helper (cdr liste)
(+ n (* (car liste) (expt 10 (1- (length liste))))))))
(defun list-to-num (liste)
(list-to-num-helper liste 0))
您可以尝试这些,看看是否有将数字转换为字符串的改进。就个人而言,我不喜欢数字字符串,因为我认为它们是我在Java时代被迫做的一个丑陋的技巧。
您还可以使用向量将这些函数转换为版本,并查看它们的用途。