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

时间:2012-04-14 14:11:06

标签: java arrays string

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

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

//这些数组应该相等

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

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

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

10 个答案:

答案 0 :(得分:28)

  • 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的“Engineering a Sort Function”,Software-Practice and Experience,Vol。 23(11)P。1249-1265(1993年11月)。该算法在许多数据集上提供n * log(n)性能,导致其他快捷方式降级为二次性能。

答案 1 :(得分:9)

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

List<String> l1 = new ArrayList<String>(Arrays.asList(s1));
List<String> l2 = new ArrayList<String>(Arrays.asList(s2));

Collections.sort(l1);
Collections.sort(l2);

boolean outcome = l1.equals(l2);

答案 2 :(得分:3)

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");
}

答案 3 :(得分:3)

以人为本:

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

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;
}

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

boolean equal(String[] arr1, String[] arr2) {
    if(arr1.length != arr2.length) return false;
    Map<String, Integer> map1 = new HashMap<String,Integer>();
    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;
}

答案 4 :(得分:3)

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

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

Bag<String> h1 = HashBag.newBagWith(s1);
Bag<String> h2 = HashBag.newBagWith(s2);
Assert.assertEquals(h1, h2);

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

注意:我是Eclipse Collections的提交者

答案 5 :(得分:1)

我想这是为了学校。

可能的策略:

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

答案 6 :(得分:1)

Set::equals

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

您不需要任何外部库。 Set<>已经有equals方法进行与订单无关的比较。

public static <T> boolean areArraysEquivalent(T[] ary1, T[] ary2) {
    if (ary1 == null) {
        return ary2 == null;
    }

    if (ary2 == null) {
        return false;
    }

    List<T> list1 = Arrays.asList(ary1);
    List<T> list2 = Arrays.asList(ary2);
    return areListsEquivalent(list1, list2);
}


public static <T> boolean areListsEquivalent(List<T> list1, List<T> list2) {
    if (list1 == null) {
        return list2 == null;
    }

    if (list2 == null) {
        return false;
    }

    Set<T> set1 = new HashSet<>(list1);
    Set<T> set2 = new HashSet<>(list2);
    return set1.equals(set2);
}

答案 7 :(得分:0)

我首先对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<s1.length;i++){
        if (! s1[i].equals(s2[i])){
            return false;
        }
    }

return true;
}

答案 8 :(得分:0)

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

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

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

答案 9 :(得分:0)

对于小型数组,我会像其他人建议的那样使用Arrays.sortArrays.equals。对于较大的阵列,您可以使用以下具有更好时间复杂度的解决方案 - 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 <T> Map<T, Integer> counts(T[] arr) {
    Map<T, Integer> map = new HashMap<>();
    for (T t : arr)
        map.merge(t, 1, Integer::sum);
    return map;
}