我注意到Clojure(1.4)似乎很高兴地将向量视为相同向量的seq
,但对于映射则不适用:
(= [1 2] (seq [1 2]))
=> true
(= {1 2} (seq {1 2}))
=> false
为什么
=
的行为会以这种方式不同呢?Clojure中的=
可以理解为通过两个步骤进行比较:
检查被比较的对象类型是否属于同一“相等划分”类,即一组可能相等的类型(根据给定数据结构的具体成员而不是分区中的特定类型);
如果是,则检查被比较的对象是否实际上相等。
“顺序”是其中一个相等划分。向量被认为是顺序的:
(instance? clojure.lang.Sequential [])
;= true
As是各种类型的序列:
(instance? clojure.lang.Sequential (seq {1 2}))
;= true
因此,只有当向量的对应元素相等时,向量才被认为等于序列。(请注意,(seq {})
会产生nil
,它不是顺序的并且与()
,[]
等比较时会“不相等”)。另一方面,映射构成自己的等价划分,因此虽然哈希映射可能被认为等于排序映射,但它永远不会被认为等于序列。特别地,它不等于其条目的序列,这就是(seq some-map)
产生的内容。mapEquals
。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)
但它们并不被视为相等 user> (= {1 2} (seq {1 2})) 错误
对于更长的映射也是如此:
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
的seq
是一个seq
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
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]
不同。