在Clojure中,合并(或检索两个列表(或序列)的并集)的惯用方法是什么?
(merge l1 l2)
看起来并不是解决方案:
a=> (merge '(1 2 3) '(2 3 4))
((2 3 4) 1 2 3)
如果你想要的是不同的未排序数据集,那么你应该使用Clojure的集合数据结构而不是向量或列表。正如andih间接建议的那样,有一个用于集合操作的核心库:http://clojure.github.com/clojure/clojure.set-api.html
(require '[clojure.set :refer [union]])
(union #{1 2 3} #{3 4 5})
=> #{1 2 3 4 5}
如果由于某些原因,集合不是您想要的内容,请继续阅读。请注意,在序列中有大量数据时,使用 concat
时要小心,并考虑使用更好优化为向量合并算法的 into
。我不知道为什么没有使用 into 来实现 concat(或者更好的是,为什么存在 concat?顺便说一下,虽然 into 比 concat 快得多,但它仍然比 conj 慢得多。Bagwell 的 RRB 树兼容 Clojure 和 Scala,将解决这个问题,但尚未为 Clojure 实现)。
用“into”重新表述Omri的非集合解决方案:
(distinct (into [1 2 3] [3 4 5]))
=> (1 2 3 4 5)
(into foo bar)
与(reduce conj foo bar)
相同,只是它将使用transients(如果可用)。 - Philip Potterconcat
肯定不能是常量时间吧?随着输入长度的增加,它必须是线性时间吧? - Petrus Theron获取两个列表的并集的一种方法是使用union
Clojure> (into #{} (clojure.set/union '(1,2,3) '(3,4,5)))
#{1 2 3 4 5}
或者如果您想要获取一个列表
(into '() (into #{} (clojure.set/union '(1,2,3) '(3,4,5))))
(5 4 3 2 1)
union
操作列表参数并不能真正实现任何目标。它只是执行 (reduce conj '(1,2,3) '(3,4,5))
。clojure.set
函数旨在处理集合参数。 - Marko Topolnik(def colls '((1 2 3) (2 3 4)))
(flatten colls) ;; => (1 2 3 2 3 4)
(distinct (flatten colls)) ;; => (1 2 3 4)
需要注意的一点是,它会扁平化深度嵌套的集合:
(flatten [[1 2 [3 4 5]] [1 [2 [3 4]]]]) ;; => (1 2 3 4 5 1 2 3 4)
(flatten [[{} {} {}] [{} {} {}]]) ;; => ({} {} {} {} {} {})
merge
已被clojure.core
占用。为避免混淆,您可以为您的merge
函数选择另一个名称。请参阅http://clojuredocs.org/clojure_core/clojure.core/merge。 - tnoda