数组忽略顺序相等

41

可能是重复问题:
Java:检查数组的相等性(顺序无关紧要)

我有两个数组:

String[] a1 = {"a", "b", "c"};
String[] a2 = {"c", "b", "a"};

我需要检查两个数组是否包含相同的元素(长度也相同),而且元素的顺序无关紧要。

我尝试了Arrays.equals(a1, a2),但它会考虑元素的顺序。org.apache.commons.lang.ArrayUtils并没有提供这个功能。

我知道可以通过创建自己的方法来实现相同的效果(先检查长度是否相同,然后对两个数组进行排序,最后使用Arrays.equals(a1, a2)),但我想知道是否有任何 API 提供此功能或者是否有更聪明的方法来实现相同的效果。


你尝试过使用Arrays.sort(a2)排序,然后检查它们是否相等吗? - CBredlow
你可以在调用Arrays.equals之前对数组进行排序,但这将是一件代价高昂的事情。 - Denys Séguret
1
可能更有效的解决方案是将第一个数组的项添加到哈希集中,然后检查第二个数组中哪些项尚未在哈希集中。 - Denys Séguret
4个回答

35
如果您在继承自Collection的东西中拥有这些数组,您可以直接使用来自Collection接口的collection.containsAll(otherCollection)。但是,您还需要比较两者的长度,以验证一个集合是否是另一个集合的超集。
(感谢Aardvarkk和piegames。)

http://docs.oracle.com/javase/6/docs/api/java/util/Collection.html#containsAll(java.util.Collection)

注意:这个方法可以起作用,但有一定限制。它被定义为检查至少存在一个元素。也就是说,如果你在一个集合中有3个a值,在另一个集合中有7个a值,这并不一定会导致它将它们视为不相等。
例子:
[a, b, c] == [c, a, b]             // Works -- Mixed order
[a, b, c, d, d] == [a, b, d, c, d] // Works -- Mixed order with repeats
[a, b, c, d, d] == [a, b, b, c, d] // FAILS -- Different repeats
[a, b, c, d, d] != [a, b, c, d]    // Works -- Length differs with repeats
[a, b, c, d] != [a, b, c]          // Works -- Length differs
[a, b, d] != [a, b, c]             // Works -- Disjoint sets

10
你需要在两个方向上检查containsAll吗?只进行单向评估,将返回一个集合是否是另一个集合的超集的true值,这似乎不是OP想要的。 - aardvarkk
4
这里存在重复项问题。尽管JavaDoc没有明确说明,但当且仅当a中包含b中每个元素x至少一次时,a.containsAll(b)才会返回true。例如,请尝试使用a={5}b={5,5}进行测试。当视为多重集时,它们不相等,但是在双向上,containsAll均返回true - Daniel Lubarov
至少这是实际使用中containsAll的解释。即使是Guava的Multiset.containsAll也“不考虑元素出现次数”。 - Daniel Lubarov
@Daniel,这部分内容已经在我的回答中的“注意事项”中涵盖了。 - BlackVegetable
2
@aardvarkk 如果没有重复项,仅检查两个数组的长度是否相等就足够了,而不需要使用第二个containsAll方法吗? - piegames
显示剩余2条评论

28

我认为这可能适合你,先使用排序方式对第一个数组进行排序

Arrays.sort(Object[]);

之后你可以与之进行比较

Arrays.equals(Object[],Object[]);

完整的代码如下:

String[] a1 = {"a", "b", "c"};
String[] a2 = {"c", "b", "a"};
Arrays.sort(a2);

boolean result= Arrays.equals(a1, a2);

3
需要在a1和a2上进行排序。不能保证a1已经排好序。 - Gaʀʀʏ
即使如此,排序并不总是一个好主意:它会改变数据。如果你不想改变原数据就必须复制数据,这将浪费时间和内存。 - piegames
如果对象没有实现可比较接口,这将无法工作。 - Dylanthepiguy

15

在比较它们之前将列表转换为集合:

new HashSet( Arrays.asList( a1 )).equals( new HashSet( Arrays.asList( a2 ) ));

或者,您可以使用Arrays.sort()对数组进行排序,但这可能会破坏依赖于数组元素顺序的代码。


17
只有没有重复的情况下,这个方法才有效。 - assylias
4
这也更有效率,因为它的运行时间复杂度为O(m+n),而在列表上执行containsAll的时间复杂度则为O(n^2+m^2)。 - Martin Andersson

2

使用java.util.Setequals方法。比较两个集合是否具有相同的大小,并且指定集合的每个成员都包含在另一个集合中。


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