在Lisp中一次处理列表中的n个项目

reb*_*oob 5 common-lisp

给定一个列表,我如何一次处理N个项目?Ruby有each_slice方法Enumerable可以做到这一点; 什么是Lisp等价物?

Jos*_*lor 5

Common Lisp loop可以非常好地用于此,如以下两个示例所示.第一个示例(x y z)在列表中循环.不过,默认的步骤是cdr(rest),所以如果列表(1 2 3 4 5),你(1 2 3),(2 3 4)等等,对(x y z).

CL-USER> (loop for (x y z) on '(1 2 3 4 5 6 7 8 9 10 11 12)
              do (print (list z y x)))

(3 2 1) 
(4 3 2) 
(5 4 3) 
(6 5 4) 
(7 6 5) 
(8 7 6) 
(9 8 7) 
(10 9 8) 
(11 10 9) 
(12 11 10) 
(NIL 12 11) 
(NIL NIL 12) 
NIL
Run Code Online (Sandbox Code Playgroud)

如果您不希望迭代之间重叠,请将步进函数指定为在列表中向下移动的内容.例如,如果您一次拉三个元素,请使用cdddr:

CL-USER> (loop for (x y z) on '(1 2 3 4 5 6 7 8 9 10 11 12) by 'cdddr
              do (print (list z y x)))
(3 2 1) 
(6 5 4) 
(9 8 7) 
(12 11 10) 
NIL
Run Code Online (Sandbox Code Playgroud)

使用此技术实现分区

另一个答案实现了each_slice使用辅助功能的对应物.但是,请注意partition(在这种意义上)只each_slice具有身份功能.这表明我们应该能够使用上面的习语来实现它.匿名功能

(lambda (list)
  (nthcdr n list))
Run Code Online (Sandbox Code Playgroud)

是我们需要的阶梯函数.由于我们不知道细胞在运行时有多少元素,我们不能像上面那样绑定每个元素(x y z).当我们下台并提取子序列n元素时,我们必须匹配列表的每个尾部.这是一个loop基础的实现partition.

CL-USER> (defun partition (list cell-size)
           (loop for cell on list by #'(lambda (list)
                                         (nthcdr cell-size list))
              collecting (subseq cell 0 cell-size)))
PARTITION

CL-USER> (partition '(1 2 3 4 5 6) 2)
((1 2) (3 4) (5 6))
Run Code Online (Sandbox Code Playgroud)