我是一名Java程序员,也是Clojure的新手。从不同的地方,我看到序列和集合在不同的情况下使用。但是,我不知道它们之间究竟有什么区别。
举个例子:
1)在Clojure的Sequence文档中:
The Seq interface
(first coll)
Returns the first item in the collection.
Calls seq on its argument. If coll is nil, returns nil.
(rest coll)
Returns a sequence of the items after the first. Calls seq on its argument.
If there are no more items, returns a logical sequence for which seq returns nil.
(cons item seq)
Returns a new seq where item is the first element and seq is the rest.
正如您所看到的,在描述Seq接口时,前两个函数(first / rest)使用coll
,这似乎表明这是一个集合,cons
函数使用{{1}这似乎表明这是一个序列。
2)有一些名为seq
和coll?
的函数可用于测试值是集合还是序列。很明显,收集和顺序是不同的。
3)在Clojure关于“Collections”的文档中,有人说:
因为集合支持seq函数,所有序列 函数可以与任何集合一起使用
这是否意味着所有集合都是序列?
seq?
上面的代码告诉我情况并非如此,因为(coll? [1 2 3]) ; => true
(seq? [1 2 3]) ; => false
是一个集合,但不是一个序列。
我认为这对于Clojure来说是一个非常基本的问题,但是我无法找到一个地方清楚地解释它们的区别是什么以及我应该在不同的情况下使用哪一个。任何评论都表示赞赏。
答案 0 :(得分:22)
支持核心first
和rest
功能的任何对象都是sequence
。
许多对象都满足此接口,并且每个Clojure集合都提供至少一种seq对象,用于使用seq
函数遍历其内容。
所以:
user> (seq [1 2 3])
(1 2 3)
您也可以从map
创建一个序列对象
user> (seq {:a 1 :b 2})
([:a 1] [:b 2])
这就是为什么您可以在filter
map
上使用for
,maps
,sets
等等。
因此,您可以将许多类似于集合的对象视为序列。
这就是为什么许多序列处理函数,例如filter
在输入上调用seq
的原因:
(defn filter
"Returns a lazy sequence of the items in coll for which
(pred item) returns true. pred must be free of side-effects."
{:added "1.0"
:static true}
([pred coll]
(lazy-seq
(when-let [s (seq coll)]
如果您致电(filter pred 5)
Don't know how to create ISeq from: java.lang.Long
RT.java:505 clojure.lang.RT.seqFrom
RT.java:486 clojure.lang.RT.seq
core.clj:133 clojure.core/seq
core.clj:2523 clojure.core/filter[fn]
您看到seq
调用此对象是序列验证。
如果你想深入了解,大部分内容都在Joy of Clojure第5章。
答案 1 :(得分:16)
每个序列都是一个集合,但不是每个集合都是一个序列。
seq
函数可以将集合转换为序列。例如。对于地图,您可以获得其条目列表。但是,该条目列表与地图本身不同。
答案 2 :(得分:13)
在Clojure for the brave and true中,作者以一种可以理解的方式对其进行总结:
集合抽象与序列密切相关 抽象。所有Clojure的核心数据结构 - 矢量,地图, 列表和集合 - 参与两个抽象。
抽象的不同之处在于序列抽象是"关于" 在集合抽象是单独操作成员 "约"数据结构整体。例如,集合 函数
count
,empty?
和every?
不是关于任何个人的 元件;他们是关于整体的。
答案 3 :(得分:10)
以下几点有助于理解集合与序列之间的区别。
“集合”和“序列”是抽象,而不是可以从给定值确定的属性。
收藏品是价值袋。
序列是一种数据结构(集合的子集),预计将以顺序(线性)方式访问。
下图最能说明它们之间的关系:
您可以详细了解here。
答案 4 :(得分:3)
seq?
:
如果x实现ISeq
,则返回true
如果x实现IPersistentCollection
,则返回true
我发现ISeq interface来自Clojure源代码中的IPersistentCollection,正如Rörd所说,每个序列都是一个集合。
答案 5 :(得分:1)
我刚刚读完“ Clojure的喜悦”的第5章-“集合类型”,这有点令人困惑(即该书的下一版本需要复习)。这是我的看法:
这只是“集合”数据类型之一(它们实际上是面向对象的对象,具有某些属性,方法和行为)。为Clojure Universe制作的实例是持久的(即不可变的),但是如果绝对必要,您也可以直接基于Java Collection类创建Collection类型的实例,这些实例是可变的。
在Clojure宇宙中有:
sequential?
产生true
的序列)
出于演示目的,使用图表:
这是函数first
和rest
可以正确处理的 (用OO术语:“实现seq API的东西”)。
这确实可能是集合,或者是应用功能seq
的结果。
如果将函数seq
应用于有意义的对象,则会得到一个 seq对象,该对象表示/生成序列,可能是“按需”,即惰性, 办法。
seq对象基本上是一个支持first
和rest
的迭代器对象。
例如,应用seq
之后,您可能会获得以下类别的对象:
clojure.lang.Cons
-尝试(class (seq (map #(* % 2) '( 1 2 3))))
clojure.lang.PersistentList
clojure.lang.APersistentMap$KeySeq
clojure.lang.PersistentList$EmptyList
clojure.lang.PersistentHashMap$NodeSeq
clojure.lang.PersistentQueue$Seq
clojure.lang.PersistentVector$ChunkedSeq
如果您通过seq
传递序列,则返回的具体类型可能与传入的具体类型不同(有时没有)。仍然是一个序列。
序列中的“元素”是什么取决于具体类型。例如,对于地图,它们是键值对,看起来像2元素vector
(但实际上是另一种具体类型)。
最后,创建一个空序列:(rest (seq [:foo]))
用于演示目的的奖励图像: