Clojure集合与序列的相等性

时间:2012-06-12 11:23:56

标签: clojure sequence equality

我注意到Clojure(1.4)似乎很乐意考虑等于同一向量的seq的向量,但这同样不适用于地图:

(= [1 2] (seq [1 2]))
=> true

(= {1 2} (seq {1 2}))
=> false

为什么=的行为会以这种方式不同?

5 个答案:

答案 0 :(得分:12)

Clojure的=可以被认为是通过两个步骤进行比较:

  1. 检查被比较的东西的类型是否属于相同的“相等分区”,即一类类型的成员可能相等(取决于给定数据结构的确切成员之类的东西,但不是分区中的特定类型);

  2. 如果是,请检查实际比较的内容是否相等。

  3. 一个这样的平等分区是“顺序”事物。向量被认为是顺序的:

    (instance? clojure.lang.Sequential [])
    ;= true
    

    与各种类型的seqs一样:

    (instance? clojure.lang.Sequential (seq {1 2}))
    ;= true
    

    因此,如果(并且仅当)它们的相应元素相等,则认为向量等于seq。

    (请注意,(seq {})生成nil顺序,并将“不等于”与()[]等进行比较。)

    另一方面,映射构成了它们自己的相等分区,因此虽然哈希映射可能被认为等于有序映射,但它永远不会被认为等于seq。特别是,它不等于其条目的seq,这是(seq some-map)产生的。

答案 1 :(得分:5)

我想这是因为序列顺序以及特定位置的值很重要,因为在映射中键/值的顺序无关紧要,语义之间的这种差异会导致它按照示例代码所示工作。 / p>

有关详细信息,请查看文件https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/APersistentMap.java

中的mapEquals

它检查另一个对象是否不是map,然后返回false。

答案 2 :(得分:3)

user=> (seq {1 2})
([1 2])
user=> (type {1 2})
clojure.lang.PersistentArrayMap

答案 3 :(得分:2)

在我看来,这个例子指出了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}))     假

对于较长的地图也是如此:

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 {1}}是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

也许理解微小的不一致是学习语言的一部分,或者有一天可以改变(虽然我不会屏住呼吸)

<小时/> 编辑:

我发现两个地图为相同的值生成不同的序列,所以只是在地图上调用seq不会给你正确的地图相等:

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> 

答案 4 :(得分:1)

(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]不同。