CommonLisp:循环列表对

CommonLisp:循环列表对,lisp,common-lisp,sbcl,Lisp,Common Lisp,Sbcl,我有一个列表,它的长度可以被2整除,我在寻找类似于这个问题的答案: (loop for (a b) on lst while b collect (+ a b)) 但是,元素之间存在重叠: (1 2 3 4 5) -> (3 5 7 9) 添加1和2,然后添加2和3,以此类推 我有一个类似(1234)的列表,我正在寻找类似 ((1 2) (3 4)) 作为输出。有没有办法使循环正确地跨过列表? 另一种解决方案。类似的解决方案应该可以: (let ((list '(1 2

我有一个列表,它的长度可以被2整除,我在寻找类似于这个问题的答案:

(loop for (a b) on lst while b
      collect (+ a b))
但是,元素之间存在重叠:

(1 2 3 4 5) -> (3 5 7 9)
添加1和2,然后添加2和3,以此类推

我有一个类似
(1234)
的列表,我正在寻找类似

((1 2) (3 4))
作为输出。有没有办法使循环正确地跨过列表?
另一种解决方案。

类似的解决方案应该可以:

(let ((list '(1 2 3 4)))
  (loop :for (a b) :on list :by #'cddr :while b 
        :collect (cons a b)))
还有一个更详细的变体:

(let ((list '(1 2 3 4)))
  (loop :for a :in list :by #'cddr
        :for b :in (cdr list) :by #'cddr
        :collect (cons a b)))

使用包的另一种方法。 另见Richard C.Waters的文章

安装程序 代码
  • 列表的内容扫描为“序列”
  • chunk
    M=2和N=2时的块:

    此函数的作用是分解输入序列项 分成(可能重叠的)长度为m的块。起始位置 连续块的数量相差n。输入m和n必须同时为 正整数

    更准确地说,
    (区块2(扫描)(1234))
    产生
    #Z(13)
    #Z(24)

  • 在这些序列的每个
    奇数
    偶数
    元素上并行映射
    ,生成一系列对,就像
    (列出奇偶)
    所做的那样

  • 最后,
    将结果收集为列表

汇编 由于流融合机制,所有中间“序列”都被编译掉了。以下是指向收集时的宏展开:

(LET* ((#:OUT-1120 LIST))
  (LET (#:ELEMENTS-1117
        (#:LISTPTR-1118 #:OUT-1120)
        (#:COUNT-1113 0)
        #:CHUNK-1114
        #:CHUNK-1115
        #:ITEMS-1123
        (#:LASTCONS-1106 (LIST NIL))
        #:LST-1107)
    (DECLARE (TYPE LIST #:LISTPTR-1118)
             (TYPE FIXNUM #:COUNT-1113)
             (TYPE CONS #:LASTCONS-1106)
             (TYPE LIST #:LST-1107))
    (SETQ #:COUNT-1113 1)
    (SETQ #:LST-1107 #:LASTCONS-1106)
    (TAGBODY
     #:LL-1124
      (IF (ENDP #:LISTPTR-1118)
          (GO SERIES::END))
      (SETQ #:ELEMENTS-1117 (CAR #:LISTPTR-1118))
      (SETQ #:LISTPTR-1118 (CDR #:LISTPTR-1118))
      (SETQ #:CHUNK-1114 #:CHUNK-1115)
      (SETQ #:CHUNK-1115 #:ELEMENTS-1117)
      (COND ((PLUSP #:COUNT-1113) (DECF #:COUNT-1113) (GO #:LL-1124))
            (T (SETQ #:COUNT-1113 1)))
      (SETQ #:ITEMS-1123
              ((LAMBDA (ODD EVEN) (LIST ODD EVEN)) #:CHUNK-1114 #:CHUNK-1115))
      (SETQ #:LASTCONS-1106
              (SETF (CDR #:LASTCONS-1106) (CONS #:ITEMS-1123 NIL)))
      (GO #:LL-1124)
     SERIES::END)
    (CDR #:LST-1107)))


这可能会变得非常慢,是否有一个非循环的宏变量可能更快?@cheshirecatalyst抱歉,不知道你的意思。它应该和其他循环选项(dolist、mapcar等)一样快,使用“:by”关键字不会使循环变慢,实际上它会减少两倍的步骤。
(defun pairs (list)
  (collect 'list
    (mapping (((odd even) (chunk 2 2 (scan 'list list))))
      (list odd even))))
(LET* ((#:OUT-1120 LIST))
  (LET (#:ELEMENTS-1117
        (#:LISTPTR-1118 #:OUT-1120)
        (#:COUNT-1113 0)
        #:CHUNK-1114
        #:CHUNK-1115
        #:ITEMS-1123
        (#:LASTCONS-1106 (LIST NIL))
        #:LST-1107)
    (DECLARE (TYPE LIST #:LISTPTR-1118)
             (TYPE FIXNUM #:COUNT-1113)
             (TYPE CONS #:LASTCONS-1106)
             (TYPE LIST #:LST-1107))
    (SETQ #:COUNT-1113 1)
    (SETQ #:LST-1107 #:LASTCONS-1106)
    (TAGBODY
     #:LL-1124
      (IF (ENDP #:LISTPTR-1118)
          (GO SERIES::END))
      (SETQ #:ELEMENTS-1117 (CAR #:LISTPTR-1118))
      (SETQ #:LISTPTR-1118 (CDR #:LISTPTR-1118))
      (SETQ #:CHUNK-1114 #:CHUNK-1115)
      (SETQ #:CHUNK-1115 #:ELEMENTS-1117)
      (COND ((PLUSP #:COUNT-1113) (DECF #:COUNT-1113) (GO #:LL-1124))
            (T (SETQ #:COUNT-1113 1)))
      (SETQ #:ITEMS-1123
              ((LAMBDA (ODD EVEN) (LIST ODD EVEN)) #:CHUNK-1114 #:CHUNK-1115))
      (SETQ #:LASTCONS-1106
              (SETF (CDR #:LASTCONS-1106) (CONS #:ITEMS-1123 NIL)))
      (GO #:LL-1124)
     SERIES::END)
    (CDR #:LST-1107)))
CL-USER 156 > (loop with list = '(1 2 3 4)
                    while list
                    collect (loop repeat 2
                                  while list
                                  collect (pop list)))
((1 2) (3 4))
CL-USER 166 > (loop with list = '(1 2 3 4 5 6)
                    while (and list (cdr list))
                    collect (loop repeat 2 collect (pop list)))
((1 2) (3 4) (5 6))

CL-USER 167 > (loop with list = '(1 2 3 4 5 6 7)
                    while (and list (cdr list))
                    collect (loop repeat 2 collect (pop list)))
((1 2) (3 4) (5 6))