使用迭代而不是递归将集合的元素分组为不相交的子集

时间:2017-02-17 14:45:34

标签: recursion common-lisp

我遇到了Pascal Bourguignon's solutions99 Lisp problems,并且想知道他是否使用嵌套的mapcan - mapcar - 构造的问题27的递归解决方案也可以使用嵌套编写环路。

他的解决方案非常优雅:

(defun group (set sizes)
  (cond
    ((endp sizes)
     (error "Not enough sizes given."))
    ((endp (rest sizes))
     (if (= (first sizes) (length set))
         (list (list set))
         (error "Cardinal mismatch |set| = ~A ; required ~A"
                (length set) (first sizes))))
    (t
     (mapcan (lambda (combi)
               (mapcar (lambda (group) (cons combi group))
                       (group (set-difference set combi) (rest sizes))))
            (combinations (first sizes) set)))))

函数combinations被定义为here

(defun combinations (count list)
  (cond
    ((zerop count) '(())) ; one combination of zero element.
    ((endp list)   '())   ; no combination from no element.
    (t (nconc (mapcar (let ((item (first list)))
                      (lambda (combi) (cons item combi)))
                    (combinations (1- count) (rest list)))
            (combinations count (rest list))))))

我从一个简单的方法开始:

(defun group-iter (set sizes)
  (loop :with size = (first sizes)
        :for subgroup :in (combination size set)
        :for remaining = (set-difference set subgroup)
        :collect (list subgroup remaining) :into result
        :finally (return result)))

导致:

> (group-iter '(a b c d e f) '(2 2 2))
 (((A B) (F E D C)) ((A C) (F E D B)) ((A D) (F E C B)) ((A E) (F D C B))
  ((A F) (E D C B)) ((B C) (F E D A)) ((B D) (F E C A)) ((B E) (F D C A))
  ((B F) (E D C A)) ((C D) (F E B A)) ((C E) (F D B A)) ((C F) (E D B A))
  ((D E) (F C B A)) ((D F) (E C B A)) ((E F) (D C B A)))

但是现在我完全没有实现嵌套,它负责remaining的进一步处理。据我所知,总有一种方法可以用迭代来表达递归,但它在这里看起来如何?

0 个答案:

没有答案