结合列表清单

时间:2015-02-13 16:43:08

标签: list lisp common-lisp

你好我必须在lisp编程这个功能:

(defun combine-list-of-lsts (lst)...)

所以在执行函数时我应该

(combine-list-of-lsts '((a b c) (+-) (1 2 3 4)))

((A + 1) (A + 2) (A + 3) (A + 4) (A-1) (A-2) (A-3) (A-4) (B + 1) (B + 2) (B + 3) (B + 4) (B-1) (B-2) (B-3) (B-4)(C + 1) (C + 2) (C + 3) (C + 4) (C-1) (C-2) (C-3) (C-4))

我现在拥有的是:

(defun combine-list-of-lsts (lst)
(if (null (cdr lst))
    (car lst)
(if (null (cddr lst))
        (combine-lst-lst (car lst) (cadr lst))
(combine-lst-lst (car lst) (combine-list-of-lsts (cdr lst))))))

使用此辅助功能:

(defun combine-lst-lst (lst1 lst2)
        (mapcan #'(lambda (x) (combine-elt-lst x lst2)) lst1))

(defun combine-elt-lst (elt lst)
            (mapcar #'(lambda (x) (list elt x)) lst))

但我得到的是:

((A (+ 1)) (A (+ 2)) (A (+ 3)) (A (+ 4)) (A(-1)) (A(-2)) (A(-3)) (A(-4))...)

我不知道怎么做但没有括号

3 个答案:

答案 0 :(得分:2)

  1. 首先要看这个案例:

    (lirs-list-of-lsts'((a b c)))

    应该是什么?也许不是你的函数返回...

  2. 然后我会看一下函数combine-list-of-lsts。您需要两个IF语句吗?

  3. 然后查看combine-elt-lst。你真的想用LIST吗?它会创建一个新列表。将元素添加到前面会不会更有意义吗?

答案 1 :(得分:1)

通常,当你想将多个参数减少为单个结果时,你需要函数#'reduce。您的列表组合具有名称cartesian n-ary product。

以下功能:

(defun cartesian (lst1 lst2)
  (let (acc)
    (dolist (v1 lst1 acc)
      (dolist (v2 lst2)
        (push (cons v1 v2) acc)))))

创建两个提供列表的笛卡尔积作为conses列表,其中#'car是lst1的元素,#'cdr是lst2的元素。

(cartesian '(1 2 3) '(- +))

==> ((3 . -) (3 . +) (2 . -) (2 . +) (1 . -) (1 . +))

但请注意,在此类产品上调用#'cartesian将返回格式错误的结果 - 缺点和元素:

(cartesian (cartesian '(1 2) '(+ -)) '(a))

==> (((1 . +) . A) ((1 . -) . A) ((2 . +) . A) ((2 . -) . A))

这种情况发生了,因为第一组的成员是conses而不是atom。另一方面,列表由conses组成,如果我们颠倒创建产品的顺序,我们可以更接近平面列表,我们的目标是什么:

(cartesian '(1 2)
           (cartesian '(+ -) '(a)))

==> ((2 + . A) (2 - . A) (1 + . A) (1 - . A))

要创建正确的列表,我们只需要使用nil来构建每个产品 - 换句话说就是创建另一个产品。

(cartesian '(1 2)
           (cartesian '(+ -)  
                      (cartesian '(a) '(nil))))

==> ((2 + A) (2 - A) (1 + A) (1 - A))

包装所有内容:你需要以相反的顺序创建连续列表的笛卡尔积,最后为'(零),使用reduce表达式可以实现什么。最终代码看起来像这样:

(defun cartesian (lst1 lst2)
  (let (acc)
    (dolist (v1 lst1 acc)
      (dolist (v2 lst2)
        (push (cons v1 v2) acc)))))

(defun combine-lsts (lsts)
  (reduce
   #'cartesian
   lsts
   :from-end t
   :initial-value '(nil)))

答案 2 :(得分:0)

还有一种方法可以尝试,

(defun mingle (x y)
 (let ((temp nil))
  (loop for item in x do
   (loop for it in y do
    (cond ((listp it) (setf temp (cons (append (cons item 'nil) it) temp)))
     (t (setf temp (cons (append (cons item 'nil) (cons it 'nil)) temp))))))
  temp))

用法:(mingle '(c d f) (mingle '(1 2 3) '(+ -))) =>

((F 1 +) (F 1 -) (F 2 +) (F 2 -) (F 3 +) (F 3 -) (D 1 +) (D 1 -) (D 2 +) (D 2 -) (D 3 +) (D 3 -) (C 1 +) (C 1 -) (C 2 +) (C 2 -) (C 3 +) (C 3 -))