【问题标题】:Can be this lisp function be implemented recursively?这个lisp函数可以递归实现吗?
【发布时间】:2016-06-22 19:04:15
【问题描述】:

此函数的目标是生成 2 个列表的笛卡尔积。 例如

  • (combo (list 1 2 3) (list 4 5)) => (1 4) (1 5) (2 4) (2 5) (3 4) (3 5)

    (defun combo (l1 l2)
    (let    (
                (res (list))
            )
        (dolist (elem1 l1 res)
            (dolist (elem2 l2 res)
                (setq res (append res (list(list elem1 elem2))))
            )
        )
    )
    

    )

如何递归实现?

【问题讨论】:

  • 可以,可以递归实现。
  • 请注意,您的功能非常低效。检查 APPEND 的使用情况。

标签: lisp common-lisp


【解决方案1】:

一个简单的递归实现是使用两个辅助函数;一个遍历L1(下面代码中的%COMBO),调用另一个函数将一个元素与L2%PRODUCT)中的每个元素配对:

(defun combo (l1 l2)
  (labels ((%product (el list &optional (acc (list)))
             (if (endp list)
                 acc
                 (%product el (rest list) (cons (list el (first list)) acc))))
           (%combo (l1 l2 &optional (acc (list)))
             (if (endp l1)
                 (nreverse acc)
                 (%combo (rest l1) l2 (nconc (%product (first l1) l2) acc)))))
    (%combo l1 l2)))

虽然迭代方法更简单且更高效。不要在循环中使用APPEND,您应该在最后反转列表。

(defun combo (l1 l2)
  (let ((res (list)))
    (dolist (e1 l1 (nreverse res))
      (dolist (e2 l2)
        (push (list e1 e2) res)))))

您也可以只使用Alexandria 中的MAP-PRODUCT 函数:

CL-USER> (ql:quickload :alexandria)
;=> (:ALEXANDRIA)
CL-USER> (use-package :alexandria)
;=> T
CL-USER> (map-product #'list (list 1 2 3) (list 4 5))
;=> ((1 4) (1 5) (2 4) (2 5) (3 4) (3 5))

【讨论】:

  • 完美。谢谢。 :)
  • 第二个解决方案中 (nreverse res) 的作用是什么?
  • @rnso PUSH 将对象添加到列表的前面,因此列表必须在末尾反转才能按顺序获得结果。在循环中使用APPEND 很糟糕,因为每次调用它时,都会创建列表的新副本。 lisp 中的列表是单链接的,因此您可以在前面添加元素来创建一个新列表,而无需复制或修改尾部,但在后面添加任何内容都需要创建新副本或破坏性地修改列表。使用 PUSHNREVERSE 是构建结果列表的常用 Common Lisp 习惯用法。
【解决方案2】:

这对于 Prolog 来说似乎很理想,尽管数据必须以不同的方式放置:

items1(1).
items1(2).
items1(3).

items2(4).
items2(5).

?- findall((A,B), (items1(A), items2(B)), L).
L = [ (1, 4), (1, 5), (2, 4), (2, 5), (3, 4), (3, 5)].

【讨论】:

    猜你喜欢
    • 2011-12-28
    • 1970-01-01
    • 1970-01-01
    • 2012-12-30
    • 2019-06-09
    • 1970-01-01
    • 2021-10-11
    • 2021-02-04
    • 1970-01-01
    相关资源
    最近更新 更多