我知道有多种方法可以使用Clojure解决排列问题。 我尝试使用Core.Logic创建DCG(明确的子句语法)但是 图书馆的DCG部分太实验性,无法正常工作。
在下面的代码中,我尝试了两种不同的方法。一个是列表理解(注释掉),类似于我在Haskell中解决这个问题的方式。
第二种方法使用MapCat将cons / first应用于每个返回值 递归调用置换。删除项目确保我不会为每个位置多次使用相同的字母。
有人可以解释列表理解方法有什么问题以及MapCat方法有什么问题。在Haskell中解释这类问题要容易得多 - 我对Clojure缺少一些看法吗?
(defn remove-item [xs]
(remove #{(first xs)} xs )
)
(defn permutation [xs]
(if (= (count xs) 1)
xs
;(for [x xs y (permutation (remove-item xs))
; :let [z (map concat y)]]
; z)
(mapcat #(map cons first (permutation (remove-item %)) ) xs)
)
)
编辑:@thumbnail已在评论中解决了MapCat子问题
答案 0 :(得分:3)
我们可以将permutation
函数简化为
(defn permutation [xs]
(if (= (count xs) 1)
xs
(for [x xs
y (permutation (remove-item xs))]
(map concat y))))
尝试在任何复数形式上使用它会产生java.lang.IllegalArgumentException: Don't know how to create ISeq from: ...
无论你想要置换什么。
有两个错误:
permutation
应该返回序列的序列,即使有
只有其中一个;因此xs
应为(list xs)
。这是导致异常的原因。 x
的给定xs
的排列,并且鉴于y
xs
的{{1}}只有x
,只有(cons x y)
。 经过纠正后,我们有了
(defn permutation [xs]
(if (= (count xs) 1)
(list xs)
(for [x xs
y (permutation (remove-item x xs))]
(cons x y))))
例如,
(permutation (range 3))
;((0 1 2) (0 2 1) (1 0 2) (1 2 0) (2 0 1) (2 1 0))
只有当所有的置换事物都不同时,上述工作才有效。在另一个极端...
(permutation [1 1 1])
;()
另外,
count
扫描整个序列。找出是否只有
一个元素,(seq (rest xs))
比(= (count xs) 1)
快。remove
中的remove-item
扫描整个序列。有
我们很难做到这一点。如果我们知道我们正在处理不同的事情,那么将它们作为一个集处理起来会更简单快捷:
(defn perm-set [xs]
(case (count xs)
0 '()
1 (list (seq xs))
(for [x xs, y (perm-set (disj xs x))]
(cons x y)))
count
是即时的,disj
几乎是恒定的时间,所以这是
更快。因此:
(perm-set (set '()))
;()
(perm-set (set (range 3)))
;((0 1 2) (0 2 1) (1 0 2) (1 2 0) (2 0 1) (2 1 0))
答案 1 :(得分:0)
我们可以通过处理原始序列中项目的索引来添加对重复项的支持。函数append-index返回一个新序列,其中索引和值现在位于向量中。例如'(\ a \ b \ c) - > '([0 \ a] [1 \ b] [2 \ c] [3 \ a])。
然后在for循环中处理这个序列,当我们想要将它从原始序列中删除时获取该项的索引,并在我们将其合并到尾部序列时获取该值。
(defn remove-nth [coll n]
(into (drop (inc n) coll) (reverse (take n coll))))
(defn append-index [coll]
(map-indexed #(conj [%1] %2) coll))
(defn permutation [xs]
(let [i-xs (append-index xs)]
(if (= (count xs) 1)
(list xs)
(for [x i-xs
y (permutation (remove-nth xs (first x)))]
(cons (last x) y)))))
感谢上一篇文章,我自己一直在努力解决排列问题,并没有考虑使用for comprehension。