Clojure 用序列 (seqs) 定义了许多算法。序列是一个逻辑列表,与大多数 Lisp 使用具体的 2 个槽结构表示列表不同,Clojure 使用 ISeq 接口允许许多数据结构以序列的形式访问其元素。 seq 函数会生成一个适合集合的 ISeq 实现。序列与迭代器不同,它们是持久且不可变的,而不是集合中的有状态游标。因此,它们的用途远不止 foreach - 函数可以消费和生成序列,它们是线程安全的,它们可以共享结构等等。
当 seq 用于实现 Iterable 的对象时,生成的序列仍然是不可变和持久的,并且将表示对数据的单次遍历。由于此遍历可能发生在惰性地,因此遍历可能会看到在调用 seq 之后发生的更改。此外,如果后备迭代器受 ConcurrentModificationException 的影响,那么生成的序列也会受其影响。当 seq 用于本机 Java 数组时,对底层数组的更改将反映在序列中 - 您必须复制源数组以获得完全的不可变性。也就是说,在 Iterable 和数组上使用 seq 仍然有很多实用程序,因为 seq 支持多遍和惰性算法。健壮的程序不应修改其上有 seq 的数组或 Iterable。
序列库中的许多函数都接受一个或多个集合,在它们上面调用 seq,然后对生成的序列进行操作。换句话说,许多这些函数接受集合,但对它们的序列进行操作。
这是主要序列函数的示例,按其功能大致分组。某些函数可以以不同的方式使用,因此出现在多个组中。在 API 部分中列出了更多内容。
从 Clojure 1.7 开始,Clojure 还提供了 转换器,这是一种用于对集合进行可组合转换的替代模型。转换器将转换的输入、处理和输出部分解耦,并允许在更多上下文中重用转换,例如 core.async 通道。下面列表中的许多序列函数在省略输入集合时将创建转换器。有关更多详细信息,请参阅转换器页面。
从较长序列中获取较短序列:distinct filter remove for keep keep-indexed
从较短序列中获取较长序列:cons concat lazy-cat mapcat cycle interleave interpose
缺少头部项目的序列:rest next fnext nnext drop drop-while nthnext for
缺少尾部项目的序列:take take-nth take-while butlast drop-last for
序列的重新排列:flatten reverse sort sort-by shuffle
创建嵌套序列:split-at split-with partition partition-all partition-by
处理序列的每个项目以创建新序列:map pmap mapcat for replace reductions map-indexed seque
从序列中提取特定编号的项目:first ffirst nfirst second nth when-first last rand-nth
从序列构建集合:zipmap into reduce set vec into-array to-array-2d frequencies group-by
将序列的项目作为参数传递给函数:apply
从序列计算布尔值:not-empty some reduce seq? every? not-every? not-any? empty?
使用谓词搜索序列:some filter
强制求值惰性序列:doseq dorun doall
检查惰性序列是否已被强制求值:realized?
来自集合的惰性序列:seq vals keys rseq subseq rsubseq
来自生产者函数的惰性序列:lazy-seq repeatedly iterate
来自常量的惰性序列:repeat range
从其他对象创建惰性序列:line-seq resultset-seq re-seq tree-seq file-seq xml-seq iterator-seq enumeration-seq