通用Lisp:循环遍历列表中的一对数据。

4

我有一个长度为偶数的列表,我正在寻找类似于这个问题的答案:

(loop for (a b) on lst while b
      collect (+ a b))

然而,元素之间存在重叠:

(1 2 3 4 5) -> (3 5 7 9)

将1和2相加,然后再将2和3相加等等。

而我有一个列表,类似于(1 2 3 4),我正在寻找类似的东西。

((1 2) (3 4))

作为输出。有没有办法使循环正确地遍历列表?另一个解决方案。

3个回答

6

类似这样的方法应该可以解决问题:

(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)))

这可能会变得非常缓慢,也许有一种非循环宏变体可以更快吗? - cheshirecatalyst
2
@cheshirecatalyst 抱歉,我不确定你的意思。它应该和其他循环选项(dolist、mapcar等)一样快,使用“:by”关键字不会使循环变慢,实际上它会减少一半的步骤。 - cybevnm

5

使用 SERIES 软件包的另一种方法。 同时还可以查看来自 Richard C. Waters 的 用户手册

设置

(ql:quickload :series)
(defpackage :stackoverflow (:use :series :cl))
(in-package :stackoverflow)

代码

(defun pairs (list)
  (collect 'list
    (mapping (((odd even) (chunk 2 2 (scan 'list list))))
      (list odd even))))
  • list的内容作为“serie”扫描一遍。
  • 使用M=2和N=2将其分块:

    此函数的效果是将输入系列项分解为长度为m的(可能重叠的)块。 连续块的起始位置相差n。输入m和n都必须是正整数。

    更准确地说,(chunk 2 2 (scan '(1 2 3 4)))会产生#Z(1 3)#Z(2 4)

  • 并行映射每个系列的oddeven元素,生成一系列夫妇,就像(list odd even)所做的那样。

  • 最后,将结果作为列表进行收集。

编译

所有中间的“series”都会通过流融合机制编译掉。以下是指向collect时的宏展开:

(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)))

2
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))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接