给定2个列表,你怎样才能生成第三个列表的输出,它的元素是L1和L2的交错集合?如果它们长度不均匀,则应该插入零孔。在第二个音符上,我该如何反转一个列表?我对LISP超级新手,只是修改现有的代码...我真的很喜欢有一个很好的解释,而不仅仅是代码。如何在LISP中插入2个列表的元素?
回答
首先,我猜你使用Common Lisp,因为它是Lisp课程中最常用的一个。所以,我的例子将在CL。如果你使用Scheme,你将得到几乎相同的代码。如果现代Clojure,它将需要一些改变,通过一个想法将是相同的。
交错
交错2只列出了必须要经过他们两个,收集轮流元素。你可以使用循环语句或递归来做到这一点。我将使用递归,因为它具有更多的功能风格,并且可以在任何lisp中使用,而不仅仅是CL。还要注意,有一个名为tail recursion的功能,它可以让您编写将被编译为循环的递归函数。
因此,对于我们的函数骨架结构将是:
(defun interleave (l1 l2)
??????
(interleave ?????))
收集在递归函数的项目,你将需要从每个调用返回他们,然后负面因素在一起(你必须有一个参数一个尾递归,这将积累价值)。所以,该功能的结束将是(cons current-value (interleave ????))
。 此外,您必须备用列表才能使用彼此的元素。您可能有其他参数,但您也可以在递归调用中交换它们。因此,代码变为:
(defun interleave (l1 l2)
?????
(cons current-value (interleave l2 l1)))
任何递归都必须在某处停止。在这种情况下,当两个列表都为空(零)时,它必须停止。 这是一个条件(让它给号码1),并且还有一些条件:
2.如果要从其中取出的列表是空的,而另一个不是,我们必须取而代之。
3.如果两个列表都不为空,则将第一个元素作为当前值并继续处理它的尾部。
只有一个更多的条件,2列表可以在:列表采取是不是空的,第二个是。但实际上我们并不关心这个,并且可以与规则编号前进3 因此,该代码(这是最后一个):
(defun interleave (l1 l2)
(cond ((and (eql l1 nil) (eql l2 nil)) nil) ;; rule #1
((eql l1 nil) (cons nil (interleave l2 l1))) ;; rule #2, current value is nil
(true (cons (first l1) (interleave l2 (rest l1)))))) ;; rule #3 in all other cases
反向
我我们将展示这个函数的两个实现:一个使用cond
,另一个使用内置的reduce
函数,这在实践中非常有用。
为cond
版本第一种方法是要经过所有的列表与递归调用,然后回去,收集要素:
(defun reverse-1-1 (li)
(if (eql li nil)
nil
(append (reverse-1-1 (rest li))
(list (first li)))))
但是,这是非常低效的,因为append为O(n),你必须通过n个元素,所以最终的复杂度是O(n^2)。
要减少它,你可以使用一个多参数的函数(并使其尾递归,如果编译器可以让你):
(defun reverse-1-2 (li)
(reverse-aux li nil))
(defun reverse-aux (li accumulator)
(if (eql li nil)
accumulator
(reverse-aux (rest li) (cons (first li) accumulator))))
这就是你用一个参数来收集你的元素,但通过该列表,然后只是返回这个累加器。
还有一个更有趣的选项。 Lisp具有非常强大的功能reduce
(在其他功能语言中,它有时被称为fold
,foldr
,foldl
或类似的东西)。您可能会发现说明它here,我会只显示一个例子:
(defun reverse-2 (li)
(reduce #'cons li :from-end t :initial-value nil))
:from-end
告诉函数要经过单从末尾,:初始值告诉作为首先减少使用论点nil
。
注意:在某些实现中,减少选项:from-end true
可能首先自行反向列表,因此如果您需要从头创建或使用最有效的版本,请改为使用reverse-1-2
。
Common Lisp中:
(defun merge-lists (lst1 lst2)
(let ((m (max (length lst1) (length lst2))))
(flatten (mapcar (lambda (a b) (list a b))
(append-nulls lst1 m)
(append-nulls lst2 m)))))
实例:
(merge-lists '(1 2 3 4) '(5 6 7 8)) ;; => (1 5 2 6 3 7 4 8)
(merge-lists '(1 2 3 4) '(5 6 7)) ;; => (1 5 2 6 3 7 4 NULL)
(merge-lists '(1 2) '(5 6 7 8)) ;; => (1 5 2 6 NULL 7 NULL 8)
的辅助函数flatten
和append-nulls
:
(defun flatten (tree)
(let ((result '()))
(labels ((scan (item)
(if (listp item)
(map nil #'scan item)
(push item result))))
(scan tree))
(nreverse result)))
(defun append-nulls (lst n)
(if (< (length lst) n)
(dotimes (i (- n (length lst)))
(setq lst (append lst (list 'null)))))
lst)
:
(defun interleave (l1 l2)
(cond ((and (eql l1 nil) (eql l2 nil)) nil) ;; rule #1
((eql l1 nil) (cons nil (interleave l2 l1))) ;; rule #2, current value is nil
(true (cons (first l1) (interleave l2 (rest l1)))))) ;; rule #3 in all other cases
如果其中一个列表比另一个长,你会得到类似于(1 2 3 4 nil 5)的东西。 替换: ((EQL L1无)(利弊零(交织L2 L1)))
用: ((空L1)L2)
:P
的更惯用的一个例子在Common Lisp中的解决方案:
(defun interleave (a b)
(flet ((nil-pad (list on-list)
(append list (make-list (max 0 (- (length on-list) (length list)))))))
(loop for x in (nil-pad a b)
for y in (nil-pad b a)
append (list x y))))
- 1. 在common-lisp中,如何将元素插入到列表中?
- 2. Lisp将一个元素插入到子列表中
- 3. 如何将列表中的元素插入到列表中?
- 4. lisp交换列表元素
- 5. Lisp,如何从列表中删除元素列表?
- 6. 在AsyncTask列表中插入元素
- 7. OCaml在列表中插入元素
- 8. 在链接列表中插入元素
- 9. LISP - 用列表中的第一个元素划分列表
- 10. 如何在有序列表中插入DOM元素(在Dojo中)?
- 11. 如何在LISP中创建列表并接受用户列表中的元素?
- 12. Lisp从列表中获取元素
- 13. 在列表中插入元素,索引包含在列表中
- 14. 将一个列表的元素插入另一个列表
- 15. 如何在任意位置插入元素到列表中?
- 16. 将元素插入到R列表中
- 17. 将列表中的每个元素与另一个列表中的每个元素相乘lisp
- 18. Android,Java:返回3个元素列表中的2个元素
- 19. 从lisp的列表中删除一个元素
- 20. 在有序链接列表中插入一个元素
- 21. 在排序和旋转列表中插入一个元素
- 22. 在每个列表元素中插入链接标签
- 23. 我如何交错scala中的2个列表的元素
- 24. 在python的列表的末尾插入一个元素?
- 25. 如何删除列表中元素的最后2个字符?
- 26. 使用Lisp将新元素推入新的空列表
- 27. 如何从common-lisp每次获取列表中的两个元素?
- 28. 将元素插入到元素列表中
- 29. 如何在数组中的每个元素之后插入一个新元素?
- 30. 在单个链接列表的末尾插入元素
我添加了“作业”标记,以确保人们给出比代码更多的解释。 – Gabe 2010-10-19 22:57:28
看到这个问题的一些提示(来自Haskell的库):http://stackoverflow.com/questions/3938438/merging-two-lists-in-haskell – 2010-10-20 06:23:03