Java:检查数组的相等性(顺序无关紧要)

我有两个String数组,让我们说:

 String[] s1 = {"a","b","c"} String[] s2 = {"c","a","b"} 

//这些数组应该相等

我想以“最干净”的方式检查他们的平等。

我尝试使用Arrays.equals(s1,s2)但我得到了一个错误的答案。 我想这个方法关心元素的顺序,我不希望这一点很重要。

你能告诉我怎样才能以一种好的方式做到这一点?

  • Arrays.sort(S1);
  • Arrays.sort(S2);
  • 满足Arrays.equals(S1,S2);

如果您不想修改原始数组

  Arrays.equals( Arrays.sort( Arrays.copyof(s1,s1.length)), Arrays.sort( Arrays.copyof(s2,s2.length)) ); 

Arrays.sort()使用优化的快速排序,nlog(n)表示平均值,但在最坏的情况下为O(n2)。 来自java文档。 所以最坏的情况是O(n2),但实际上大多数情况下都是O(nlogn)。

排序算法是一个经过调整的快速排序,改编自Jon L. Bentley和M. Douglas McIlroy的“工程排序function”,软件实践和经验,卷。 23(11)P。1249-1265(1993年11月)。 该算法在许多数据集上提供n * log(n)性能,导致其他快速降序降级为二次性能。

其他人建议对数组进行排序。 但是既然你正在寻找“最干净”的解决方案,我认为不应该触及原始arrays。 因此:

 List l1 = new ArrayList(Arrays.asList(s1)); List l2 = new ArrayList(Arrays.asList(s2)); Collections.sort(l1); Collections.sort(l2); boolean outcome = l1.equals(l2); 
 String[] s1 = {"a","b","c"}; String[] s2 = {"b","c","a"} ; Arrays.sort(s1); Arrays.sort(s2); if(Arrays.equals(s1, s2)){ System.out.println("ok"); } 

如果您正在使用Eclipse Collections (以前称为GS Collections ),则可以使用Bag来确定两个数组是否相等。

 String[] s1 = {"a", "b", "c", "c"}; String[] s2 = {"c", "a", "b", "c"}; Bag h1 = HashBag.newBagWith(s1); Bag h2 = HashBag.newBagWith(s2); Assert.assertEquals(h1, h2); 

如果包(也称为多重集)与每个元素的出现次数相同,则认为它们是相等的。 顺序无关紧要,它正确处理重复元素。 使用由哈希表支持的包的优点是创建一个包需要线性时间。 排序都需要O(n log n)。

注意:我是Eclipse Collections的提交者

人性化的方式:

迭代第一个数组,检查第二个数组中每个元素是否存在,然后对第一个数组中的第二个数组执行相同操作。 时间:n ^ 2。 请注意,此方法假定不重复任何元素。 如果是的话,你必须为你正在检查的每个元素返回到开头并计算该元素的实例数(比如说X),并且只计算成功,因为找到了第X个元素。第二arrays。 这样做可以消除第二次检查的需要,并留给读者练习(如果你这么倾向,那就是。)

 boolean equal(String[] arr1, String[] arr2) { if(arr1.length != arr2.length) return false; // obviously main_loop: for(int i = 0; i < arr1.length; i++) { for(int j = 0; j < arr2.length; j++) { if(arr1[i].equals(arr2[j])) break main_loop; } return false; } main_loop: for(int i = 0; i < arr2.length; i++) { for(int j = 0; j < arr1.length; j++) { if(arr2[i].equals(arr1[j])) break main_loop; } return false; } // having got through both loops, we can now return true } 

一种更高级的方法:对两个数组进行排序并遍历它们。 时间:n lg n

 boolean equals(String[] arr1, String[] arr2) { if(arr1.length != arr2.length) return false; String[] copy1 = Arrays.copyOf(arr1,arr1.length); // java.util.Arrays String[] copy2 = Arrays.copyOf(arr2,arr2.length); // java.util.Arrays Arrays.sort(copy1); Arrays.sort(copy2); for(int i = 0; i < copy1.length; i++) { if(!copy1[i].equals(copy2[i]) return false; } return true; } 

一种更高级的方法:使用散列映射,添加第一个字符串数组的计数,删除第二个字符串数组的计数。 当你是odne时,所有的计数都应该为零。

 boolean equal(String[] arr1, String[] arr2) { if(arr1.length != arr2.length) return false; Map map1 = new HashMap(); for(String str : arr1) { if(!map.containsKey(str)) { map.put(str, 1); } else { map.put(str, map.get(str) + 1); // add to count inthe map } } for(String str : arr1) { if(!map.containsKey(str)) { return false; // we have an element in arr2 not in arr1 - leave now } else { map.put(str, map.get(str) - 1); // remove to count inthe map } } for(Integer count : map.values()) { if(count.intValue() != 0) return false; } return true; } 

我想这是为了学校。

可能的策略:

  • 使用Arrays.sort对两个数组进行排序,然后使用循环将s1 [i]与s2 [i]进行比较
  • 使用循环并为s1的每个项目查看s2的项目以查找它是否包含相同的内容
  • 将s1的项目放入一个hashset,然后在s2上使用一个循环,看看你的项目是否在s1中

Set::equals

注意:这是一个简单的非侵入式解决方案,但只有在您确定任何一个输入数组/列表中没有重复条目(或者您想忽略重复项)时它才有效。

您不需要任何外部库。 Set<>已经有一个equals方法,可以进行与顺序无关的比较。

 public static  boolean areArraysEquivalent(T[] ary1, T[] ary2) { if (ary1 == null) { return ary2 == null; } if (ary2 == null) { return false; } List list1 = Arrays.asList(ary1); List list2 = Arrays.asList(ary2); return areListsEquivalent(list1, list2); } public static  boolean areListsEquivalent(List list1, List list2) { if (list1 == null) { return list2 == null; } if (list2 == null) { return false; } Set set1 = new HashSet<>(list1); Set set2 = new HashSet<>(list2); return set1.equals(set2); } 

我先排序2个数组,然后逐行比较……

 public boolean areArraysEqual (String[] array1,String[] array2){ if (s1.length != s2.length){ return false; } java.util.Arrays.sort(s1); java.util.Arrays.sort(s2); for (int i=0;i 

如果人们经常想要在不修改内容的情况下相互比较数组,那么定义封装不可变数组的类型,其排序版本,保证唯一且至少大部分与之相关的long序列计数可能会有所帮助。对象年龄,以及对已知匹配的另一个旧对象的初始空引用。 缓存组合所有数组元素的哈希值的哈希值也可能有所帮助。

使用这种方法,第一次将对象与其他东西(任何东西)进行比较时需要进行排序,但之后不会。 此外,如果发现对象X和Y都等于Z,则X和Y之间的比较可以将它们报告为相等,而不必实际检查数组内容(如果Z比X和Y更旧,则两者都将报告为相等对于相同的旧对象;如果X是最年轻的,Y是最老的,X将知道它等于Z,Z将知道它等于Y.当X与下一个相比时,它会发现它最古老的东西已知等于是Y,所以它当然等于Y.

这种方法会产生类似于实习的平等比较性能优势,但不需要实习词典。

对于小型数组,我会像其他人建议的那样使用Arrays.sortArrays.equals 。 对于较大的arrays,您可以使用以下具有更好时间复杂度的解决方案 – O(n)而不是O(n log n)

 public static boolean haveSameElements(Object[] arr1, Object[] arr2) { return arr1.length == arr2.length && counts(arr1).equals(counts(arr2)); } // Map.merge and method references require Java 8 private static  Map counts(T[] arr) { Map map = new HashMap<>(); for (T t : arr) map.merge(t, 1, Integer::sum); return map; }