【问题标题】:Pure functional code for the sublists of a list列表子列表的纯功能代码
【发布时间】:2018-02-27 22:31:54
【问题描述】:

下面的代码给了我一个列表的子列表列表。代码仍然可以改进以避免使用append,对吧?

(defun sublists (alist)
  (labels ((aux (list p r)
             (if (null list)
                 (append r (maplist #'identity p))
                 (aux (cdr list)
                      (append p (list (car list)))
                      (append r (maplist #'identity p))))))
    (aux alist nil nil)))


CL-USER> (sublists (list 1 2 3 4))
((1) (1 2) (1 2 3) (1 2 3 4) (2) (2 3) (2 3 4) (3) (3 4) (4))

想法?

编辑:请注意,我们实际上是在谈论子列表,而不是子集。也就是说,(1 2) 是子列表,但 (2 4) 不是子列表。

【问题讨论】:

标签: functional-programming common-lisp


【解决方案1】:

返回值是一个长度为n*(n-1)/2的列表的平均值列表 长度n/3 因此算法必然是渐近三次的。

您的算法似乎是四次的,因为您遍历 r(其中 在append 循环中增长为O(n^3))。

因此,如果您通过使用两个指针遍历列表来避免append 在它们之间复制子列表,您将消除额外的订单 渐近复杂度。

有趣的是,内存方面你已经是最优的了(IOW,你 不能用nconc替换append):

(setq *print-circle* t)
(sublists (list 1 2 3 4))
==> ((1) (1 . #1=(2)) #1# (1 . #2=(2 . #3=(3))) 
     #2# #3# 
     (1 . #4=(2 . #5=(3 . #6=(4))))
     #4# #5# #6#)

这是我的功能版本:

(defun sublists-head (list)
  "Return all sublists starting with the 1st element"
  (and list
       (cons (list (first list))
             (mapcar (lambda (sublist)
                       (cons (first list)
                             sublist))
                     (sublists-head (rest list))))))

(defun sublists-3 (list)
  "Return all sublists in a cubic algorithm."
  (mapcon #'sublists-head list))

唉,这失去了内存共享:虽然结果是一样的:

(set-exclusive-or (sublists-4 '(1 2 3 4)) (sublists-3 '(1 2 3 4)) :test #'equal)
NIL

所有返回的子列表都是新鲜的。

【讨论】:

  • 您说“因此,如果您通过使用两个指针遍历列表并在它们之间复制子列表来避免追加,您将消除一个额外的渐近复杂度。”,这是我最初的问题。我会对它的实际实施感兴趣。
【解决方案2】:

如果您想编写复杂的代码,请使用“reverse”。

(defun get-takes (list) (mapcar #'reverse
                                (maplist #'identity (reverse list))))

(defun get-drops (list) (maplist #'identity list))

(defun sublists (list)
  (apply #'append
         (mapcar #'get-drops (get-takes list))))

或者,

(flet ((get-takes (list) (mapcar #'reverse
                                 (maplist #'identity (reverse list))))
       (get-drops (list) (maplist #'identity list)))
  (defun sublists (list)
    (apply #'append (mapcar #'get-drops (get-takes list)))))

或者,不推荐,

(defun sublists (list)
  (apply #'append
         (mapcar (lambda (list) (maplist #'identity list))
                 (mapcar #'reverse
                         (maplist #'identity (reverse list))))))

【讨论】:

  • APPLY 将施加长度限制 > call-arguments-limit .
  • 最好在 DEFUN 中移动 FLET。
猜你喜欢
  • 2012-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-21
  • 1970-01-01
  • 1970-01-01
  • 2013-12-05
相关资源
最近更新 更多