在Clojure中比较两个向量,无论项目的顺序如何。

16

我想比较两个向量,并确定它们拥有的项是否相同,无论这些项的顺序如何。

所以...

现在在Clojure中:

(= [1 2 3] [3 2 1]) ;=> false
我想要:
(other_fun [1 2 3] [3 2 1]) ;=> true

(other_fun [1 2 3 4] [3 2 1]) ;=> false

我找不到类似于Java中的containsAll方法

6个回答

32

如果您关心重复项,您可以比较它们的频率映射。这些是具有每个集合元素作为键和出现次数作为值的映射。您可以使用标准函数 frequencies 创建它们,就像在给定示例中一样。

不同的顺序,相同数量的重复项:

(= (frequencies [1 1 2 3 4])(frequencies [4 1 1 2 3]))

计算结果为true

不同的顺序,不同数量的重复项:

(= (frequencies [1 1 2 3 4])(frequencies [4 1 2 3]))

计算结果为false

因此,您可以编写一个函数:

(defn other_fun [& colls]
  (apply = (map frequencies colls)))

1
也适用于地图! - kopos
由于Clojure的等式比较是按值进行的,因此=确实适用于像映射这样更复杂的结构。这是一个非常有用的语言设计决策:注重生产力而非性能。如果需要,您仍然可以使用identical?按指针进行比较。 - Ory Band

19

如果您不关心重复内容,可以从两个向量中创建集合并进行比较:

(= (set [1 2 3]) (set [3 2 1])) ;=> true

作为一个函数:

(defn set= [& vectors] (apply = (map set vectors)))

我知道这很老,但有点棘手,因为set会自动去重,所以例如(=(set [1 2 3])(set [1 2 3 3]))也会返回true。我认为频率答案可能更好一些。 - user3467713

11

如果您不关心重复项,则其他答案完全适用且有效。 但是,如果您关心重复项,比较两个向量的最简单方法可能是排序和比较:

user=> (= (sort [3 5 2 2]) (sort [2 2 5 3]))
true
user=> (= (sort [3 5 2 2]) (sort [2 5 3]))
false

5
从它们中创建集合:
user=> (= (set [1 2 3]) (set [3 2 1]))
true


user=> (defn other_func [col1 col2]
        (= (set col1) (set col2)))
#'user/other_func
user=> (other_func [1 2 3] [3 2 1])
true

3

你已经在JVM上了,所以如果你想使用containsAll,那么只需使用containsAll,对吧?


1
containsAll 确定一个集合是否是另一个集合的子集,但它不确定集合相等。 - Confusion
4
你可以使用 a.containsAll(b) && b.containsAll(a)。这句话的意思是判断集合a是否包含集合b的所有元素以及集合b是否包含集合a的所有元素,如果两个条件都成立,则返回true。 - bfontaine

1
(defn other_fun
  "checkes the presence of the elements of vec1 in vec2 and vice versa"
  [vec1 vec2]
  (if (or (some nil?
             (for [a vec1 b [vec2]]  (some #(= % a) b)))
       (some nil?
             (for [a vec2 b [vec1]]  (some #(= % a) b))))
    false
    true))

(other_fun [1 2 3] [3 2 1]) ;=> true

(other_fun [1 2 3 4] [3 2 1]) ;=> false

2
你可以将(if x false true)简化为(not x) - bfontaine

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接