假设我有集合
例如,如果我的忽略列表是
当然,我可以先找到完整的笛卡尔积,然后删除有问题的项,但我想要一种更有效的方法,以避免首先检查解决方案。
我有一个初始解决方案,涉及逐步构建笛卡尔积中的每个项,并在每个阶段从
为了具体起见,我的Clojure实现是:
A_1,...A_n
,例如[[a b c][d e][f]]
。我想找到这些集合的笛卡尔积,但不包括任何超集的元素在某些忽略列表中。例如,如果我的忽略列表是
[[a e][c]]
,笛卡尔积的结果将是[[a d f][b d f][b e f]]
。请注意,任何带有c
的项都不在其中,[a e f]
也不在其中。当然,我可以先找到完整的笛卡尔积,然后删除有问题的项,但我想要一种更有效的方法,以避免首先检查解决方案。
我有一个初始解决方案,涉及逐步构建笛卡尔积中的每个项,并在每个阶段从
A_i
中删除任何元素,如果将它们添加到正在构建的项会导致它成为任何一个忽略的超集。这样做效果很好,比朴素的解决方案好,但仍然有大量冗余检查,而且还取决于呈现集合的顺序。例如,如果[f]
在我的忽略列表中,我仍然会继续尝试创建术语,直到我达到[f]
然后丢弃。为了具体起见,我的Clojure实现是:
(defn first-elements
"Get the first elements of a set of sets, unless ignored"
[sets ignores in-ignore?]
(loop [product-tuple [] sets sets]
(println "sets " sets)
(cond
(or (nil? sets) (nil? (first sets)))
product-tuple
:else
(if-let [set-op (remove #(in-ignore? product-tuple ignores %) (first sets))]
(if (and (coll? set-op) (empty? set-op))
product-tuple
(recur (conj product-tuple (first set-op)) (next sets)))
product-tuple))))
(defn in-ignore?
"if I add elem to this build will it become a superset of any of the ignores"
[build ignores elem]
(some #(clojure.set/superset? (conj (set build) elem) %) ignores))
(defn cartesian-product-ignore
"All the ways to take one item from each sequence, except for ignore"
[ignores original-sets]
(loop [cart-prod #{} sets original-sets]
(let [firsts (first-elements sets ignores in-ignore?)]
(print "firsts " firsts "-cart-prod " cart-prod " sets " sets "\n")
(cond
(zero? (count firsts))
cart-prod
(= (count sets) (count firsts))
(recur (conj cart-prod firsts) (update-in sets [(dec (count sets))] next))
:else
(recur cart-prod (assoc
(update-in sets [(dec (count firsts))] next)
(count firsts)
(original-sets (count firsts))))))))