user=> (map (fn [x] (.toUpperCase x)) (.split "Dasher Dancer Prancer" " "))
("DASHER" "DANCER" "PRANCER")
Clojure 拥有丰富的集合数据结构,它们共享以下特性:
它们是不可变的
它们是可读的
它们在 equals 的实现中支持正确的值相等语义
它们提供良好的哈希值
此外,集合还:
通过接口进行操作。
支持排序
支持持久化操作。
支持元数据
实现 java.lang.Iterable
实现 java.util.Collection 或 java.util.Map 的非可选(只读)部分
nil 是 Clojure 中任何数据类型可能的值。nil 的值与 Java 中的 null 相同。Clojure 的条件系统以 nil 和 false 为基础,其中 nil 和 false 代表条件测试中的逻辑假值 - 其他任何值都是逻辑真值。此外,nil 在序列协议中用作序列结束的哨兵值。
Clojure 默认情况下完全支持 JVM 原生值,允许在数字应用中使用高效的 Clojure 代码。
Clojure 还支持从 java.lang.Number 派生的 Java 封装数字类型,包括 BigInteger 和 BigDecimal,以及它自己的 Ratio 类型。有一些特殊的处理方法
默认情况下,Clojure 使用 Java 的 long 原生类型来表示自然数。当原生整型操作的结果值超过原生类型所能容纳的范围时,会抛出 java.lang.ArithmeticException 异常。Clojure 提供了一组后缀为单引号的备用数学运算符:+',-',*',inc' 和 dec'。这些运算符在溢出时会自动提升到 BigInt,但效率低于常规数学运算符。
Clojure 字符串是 Java 字符串。另请参见 打印。
user=> (map (fn [x] (.toUpperCase x)) (.split "Dasher Dancer Prancer" " "))
("DASHER" "DANCER" "PRANCER")
所有 Clojure 集合都是不可变的,并且是 持久化的。特别是,Clojure 集合支持高效地创建“修改”后的版本,通过利用结构共享,并为持久化使用提供所有性能保证。集合高效且本质上是线程安全的。集合由抽象表示,可能存在一个或多个具体实现。特别是,由于“修改”操作会产生新的集合,因此新集合可能与源集合的具体类型不同,但将具有相同的逻辑(接口)类型。
Clojure 提供了它自己的哈希计算,这些计算为集合(和其他类型)提供了更好的哈希属性,称为 *hasheq* 值。
IHashEq
接口标记提供 hasheq()
函数以获取 hasheq 值的集合。在 Clojure 中,hash 函数可用于计算 hasheq 值。
有序集合(向量、列表、序列等)必须使用以下算法来计算 hasheq(其中 hash 计算 hasheq)。请注意,unchecked-add-int 和 unchecked-multiply-int 用于获得整数溢出计算。
(defn hash-ordered [collection]
(-> (reduce (fn [acc e] (unchecked-add-int
(unchecked-multiply-int 31 acc)
(hash e)))
1
collection)
(mix-collection-hash (count collection))))
无序集合(映射、集合)必须使用以下算法来计算 hasheq。映射项被视为键和值的顺序集合。请注意,unchecked-add-int 用于获得整数溢出计算。
(defn hash-unordered [collection]
(-> (reduce unchecked-add-int 0 (map hash collection))
(mix-collection-hash (count collection))))
mix-collection-hash 算法是实现细节,可能会发生变化。
映射是将键映射到值的集合。提供了两种不同的映射类型 - 哈希和排序。哈希映射需要正确支持 hashCode 和 equals 的键。排序映射需要实现 Comparable 的键,或 Comparator 的实例。哈希映射提供更快的访问(log32N 跳跃)与(logN 跳跃),但排序映射是,排序的。count 是 O(1)。conj 将另一个(可能是单个条目)映射作为项目,并返回一个新映射,该映射是旧映射加上新映射的条目,这可能会覆盖旧映射的条目。conj 还接受 MapEntry 或两个项目(键和值)的向量。seq 返回映射条目的序列,它们是键/值对。排序映射还支持 rseq,它以相反顺序返回条目。映射实现 IFn,用于一个参数的 invoke()(一个键)以及可选的第二个参数(一个默认值),即映射是其键的函数。nil 键和值是可以的。
创建新映射:hash-map sorted-map sorted-map-by
'更改' 映射:assoc dissoc select-keys merge merge-with zipmap
检查映射:get contains? find keys vals map?
检查映射条目:key val
大多数 StructMaps 的使用现在将通过 记录 获得更好的服务。 |
通常,许多映射实例具有相同的基本键集,例如当映射用作结构或对象时,会在其他语言中。StructMaps 支持此用例,通过有效地共享键信息,同时还提供对这些键的可选增强性能访问器。StructMaps 在所有方面都是映射,支持相同的功能集,与所有其他映射互操作,并且是持久可扩展的(即,StructMaps 不限于其基本键)。唯一的限制是您不能从 StructMaps 中分离其基本键之一。StructMaps 将按顺序保留其基本键。
StructMaps 是通过首先使用 create-struct 或 defstruct 创建结构基础对象,然后使用 struct-map 或 struct 创建实例来创建的。
(defstruct desilu :fred :ricky)
(def x (map (fn [n]
(struct-map desilu
:fred n
:ricky 2
:lucy 3
:ethel 4))
(range 100000)))
(def fred (accessor desilu :fred))
(reduce (fn [n y] (+ n (:fred y))) 0 x)
-> 4999950000
(reduce (fn [n y] (+ n (fred y))) 0 x)
-> 4999950000
StructMap 设置:create-struct defstruct accessor
创建单个结构:struct-map struct
在进行代码形式操作时,通常需要一个映射,它可以保持键顺序。数组映射就是这样的映射 - 它只是实现为一个键 val 键 val… 的数组。因此,它具有线性查找性能,仅适用于非常小的映射。它实现了完整的映射接口。可以使用 array-map 函数创建新的数组映射。请注意,只有在未“修改”时,数组映射才会保持排序顺序。后续的 assoc 操作最终会导致它“变为”哈希映射。
集合是唯一值的集合。
哈希集合有文字支持
#{:a :b :c :d}
-> #{:d :a :b :c}
您可以使用 hash-set 和 sorted-set 函数创建集合
(hash-set :a :b :c :d)
-> #{:d :a :b :c}
(sorted-set :a :b :c :d)
-> #{:a :b :c :d}
您还可以使用 set 函数获取集合中值的集合
(set [1 2 3 2 1 2 3])
-> #{1 2 3}
集合是集合
(def s #{:a :b :c :d})
(conj s :e)
-> #{:d :a :b :e :c}
(count s)
-> 4
(seq s)
-> (:d :a :b :c)
(= (conj s :e) #{:a :b :c :d :e})
-> true
集合支持使用 disj 进行“删除”,以及contains? 和get,后者返回与键比较相等的集合中包含的对象(如果找到)
(disj s :d)
-> #{:a :b :c}
(contains? s :b)
-> true
(get s :a)
-> :a
集合是其成员的函数,使用get
(s :b)
-> :b
(s :k)
-> nil
Clojure 提供了基本的集合操作,如 union / difference / intersection,以及一些针对“关系”的伪关系代数支持,这些关系只是映射集 - select / index / rename / join。