我注意到 Clojure (1.4) 似乎乐于考虑向量等于seq
同一向量的 ,但同样不适用于地图:
(= [1 2] (seq [1 2]))
=> true
(= {1 2} (seq {1 2}))
=> false
为什么要=
以这种方式不同的行为?
Clojure=
可以被认为是分两步进行比较:
检查被比较的事物的类型是否属于相同的“相等分区”,即成员可能相等的一类类型(取决于给定数据结构的确切成员之类的东西,但不是特定类型分区);
如果是这样,请检查被比较的事物是否实际上是相等的。
一种这样的平等划分是“顺序”事物的划分。向量被认为是连续的:
(instance? clojure.lang.Sequential [])
;= true
各种类型的序列也是如此:
(instance? clojure.lang.Sequential (seq {1 2}))
;= true
因此,当(且仅当)其对应元素相等时,向量才被视为等于 seq。
(请注意,(seq {})
产生nil
,它不是连续的,并且将“不等于”与()
等进行比较[]
)
另一方面,映射构成了它们自己的相等分区,因此虽然哈希映射可能被认为等于排序映射,但它永远不会被认为等于序列。特别是,它不等于其条目的 seq,这是(seq some-map)
产生的。
我想这是因为在序列中的顺序以及特定位置的值很重要,而在 map 中,键/值的顺序无关紧要,语义之间的这种差异会导致它如示例代码所示那样工作。
有关更多详细信息,请查看mapEquals
文件https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/APersistentMap.java
它检查另一个对象是否不是映射,然后返回 false。
user=> (seq {1 2})
([1 2])
user=> (type {1 2})
clojure.lang.PersistentArrayMap
在我看来,这个例子指出了 clojure 中值相等概念的轻微不一致,因为它们是从同一类型(通过seq
函数)派生的不同类型。可以说这并没有矛盾,因为它将派生类型与其派生的类型进行比较,我可以理解,如果使用向量将相同的逻辑应用于同一个示例(请注意底部)
内容是相同的类型:
user> (type (first (seq {1 2})))
clojure.lang.MapEntry
user> (type (first {1 2}))
clojure.lang.MapEntry
user> (= (type (first {1 2})) (type (first (seq {1 2}))))
true
user> (= (first {1 2}) (first (seq {1 2})))
true
序列具有相同的值
user> (map = (seq {1 2}) {1 2})
(true)
但他们不被视为平等用户> (= {1 2} (seq {1 2})) false
对于较长的地图也是如此:
user> (map = (seq {1 2 3 4}) {1 2 3 4})
(true true)
user> (map = (seq {1 2 3 4 5 6}) {1 2 3 4 5 6})
(true true true)
user> (map = (seq {9 10 1 2 3 4 5 6}) {9 10 1 2 3 4 5 6})
(true true true true)
即使它们的顺序不同:
user> (map = (seq {9 10 1 2 3 4 5 6}) {1 2 3 4 5 6 9 10})
(true true true true)
但如果包含的类型不同,则不是:-(
user> (= {1 2 3 4} (seq {1 2 3 4}))
false
编辑:这并不总是正确的,见下文:要解决这个问题,您可以在比较之前将所有内容转换为 seq,这是(我认为)安全的,因为 seq 函数总是以相同的方式迭代整个数据结构并且结构是不可变的值aseq
的 aseq
是 aseq
user> (= (seq {9 10 1 2 3 4 5 6}) {1 2 3 4 5 6 9 10})
false
user> (= (seq {9 10 1 2 3 4 5 6}) (seq {1 2 3 4 5 6 9 10}))
true
user> (= [1 2 3 4] (seq [1 2 3 4]))
true
也许理解细微的不一致是学习语言的一部分,或者有一天这可能会改变(尽管我不会屏住呼吸)
我发现两个映射为相同的值产生不同的序列,因此仅在映射上调用 seq 不会为您提供正确的映射相等性:
user> (seq (zipmap [3 1 5 9][4 2 6 10]))
([9 10] [5 6] [1 2] [3 4])
user> (seq {9 10 5 6 1 2 3 4})
([1 2] [3 4] [5 6] [9 10])
user>
这是我所说的正确映射相等的示例:
user> (def a (zipmap [3 1 5 9][4 2 6 10]))
#'user/a
user> (def b {9 10 5 6 1 2 3 4})
#'user/b
user> (every? true? (map #(= (a %) (b %)) (keys a)))
true
(seq some-hash-map)
为您提供一系列条目(键/值对)。
例如:
foo.core=> (seq {:a 1 :b 2 :c 3})
([:a 1] [:c 3] [:b 2])
这与[:a 1 :b 2 :c 3]
.