将元素放在集合的尾部

时间:2011-04-20 17:45:22

标签: collections clojure

我发现自己做了很多事情:

(concat coll [e])其中coll是一个集合,而e是一个元素。

在Clojure中有没有这样做的功能?我知道conj对矢量做的最好,但我不知道前面会使用哪种coll。例如,它可以是矢量,列表或排序集。

4 个答案:

答案 0 :(得分:52)

某些类型的集合可以廉价地添加到前面(列表,seq),而其他类型的集合可以廉价地添加到后面(向量,队列,有点类型lazy-seqs)。如果可能的话,你应该安排使用其中一种类型(向量是最常见的)并且只是联合起来而不是使用concat:(conj [1 2 3] 4)产生[1 2 3 4],而(conj '(1 2 3) 4)产生{(4 1 2 3) {1}}。

答案 1 :(得分:14)

concat不会在集合的尾部添加元素,也不会连接两个集合。

concat返回由两个其他seq的串联组成的seq。对于concat的返回类型,可以推断出可以推断出seq的集合的原始类型。

现在,为了编写高效的代码,clojure集合具有必须知道的不同属性,这就是为什么核心中没有可用于将任何类型的集合连接在一起的通用函数的原因。 相反,列表和向量确实具有“自然插入位置”,它们知道并且做了适合于该类集合的内容。

答案 2 :(得分:6)

这是@ amalloy答案的一个非常小的附录,以解决OP对一个功能的要求,这个功能总是会增加任何类型的集合。这是(concat coll [x])的替代方案。只需创建原始集合的矢量版本:

(defn conj*
  [s x]
  (conj (vec s) x))

警告:

如果你从一个懒惰的序列开始,你现在已经破坏了懒惰 - 即。输出不是懒惰的。根据您的需要,这可能是好事还是坏事。

创建矢量需要一些成本。如果您需要经常调用此函数,并且您发现(例如通过使用Criterium进行基准测试)此成本对于您的目的而言非常重要,那么请按照其他答案的建议尝试首先使用向量。

答案 3 :(得分:5)

提炼出amalloy和Laurent Petit已经说过的最好的东西:使用conj函数

Clojure提供的一个很棒的抽象是Sequence API,它包含conj函数。如果可能的话,您的代码应尽可能与集合类型无关,而是使用seq API处理集合上的操作,并仅在需要特定时才选择特定的集合类型。

如果向量是一个很好的匹配,那么是的,conj将添加项目到最后。如果改为使用列表,那么conj会将内容添加到您的收藏集的前面。但是如果你然后使用标准的seq API函数从集合的“顶部”(向量的后面,列表的前面)中提取项目,那么使用哪个实现并不重要,因为它总是会使用具有最佳性能的那个,因此添加和删除项目将是一致的。