如何将数组列表的相等性与现代 Java 进行比较?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35408290/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 00:06:52  来源:igfitidea点击:

How to compare equality of lists of arrays with modern Java?

javaarrayslistjava-8equals

提问by hyde

I have two lists of arrays.

我有两个数组列表。

How do I easily compare equality of these with Java 8 and its features, without using external libraries? I am looking for a "better" (higher-level, shorter, more efficient) solution than brute-force code like this (untested code, may contain typos etc, not the point of the question):

如何在不使用外部库的情况下轻松地将这些与 Java 8 及其功能的相等性进行比较?我正在寻找一个“更好”(更高级别、更短、更有效)的解决方案,而不是像这样的蛮力代码(未经测试的代码,可能包含拼写错误等,不是问题的重点):

boolean compare(List<String[]> list1, List<String[]> list2) 
{
    // tests for nulls etc omitted
    if(list1.size() != list2.size()) {
       return false;
    }
    for(i=0; i<list1.size(); ++i) {
        if(!Arrays.equals(list1.get(i), list2.get(i))) {
            return false;
        }
    }
    return true;
}

Or, if there isn't any nicer way, that's a valid answer too.

或者,如果没有更好的方法,那也是一个有效的答案。

Bonus: If Java 9 offers an even better way what whaterver Java 8 can offer, feel free to mention it as well.

奖励:如果 Java 9 提供了 Java 8 所能提供的更好的方式,也请随意提及。

Edit:After looking at the comments, and seeing how this question has become moderately hot, I think the "better" should include first checking lengths of all arrays, before checking array contents, because that has potential to find inequality much quicker, if inner arrays are long.

编辑:在查看评论并看到这个问题如何变得温和之后,我认为更好”应该包括在检查数组内容之前首先检查所有数组的长度,因为这有可能更快地找到不等式,如果是内部的数组很长。

采纳答案by Dragan Bozanovic

1)Solution based on Java 8 streams:

1)基于Java 8流的解决方案:

List<List<String>> first = list1.stream().map(Arrays::asList).collect(toList());
List<List<String>> second = list2.stream().map(Arrays::asList).collect(toList());
return first.equals(second);

2)Much simpler solution (works in Java 5+):

2)更简单的解决方案(适用于Java 5+):

return Arrays.deepEquals(list1.toArray(), list2.toArray());

3)Regarding your new requirement (to check the contained String arrays length first), you could write a generic helper method that does equality check for transformed lists:

3)关于您的新要求(首先检查包含的字符串数组长度),您可以编写一个通用的辅助方法来对转换后的列表进行相等性检查:

<T, U> boolean equal(List<T> list1, List<T> list2, Function<T, U> mapper) {
    List<U> first = list1.stream().map(mapper).collect(toList());
    List<U> second = list2.stream().map(mapper).collect(toList());
    return first.equals(second);
}

Then the solution could be:

那么解决方案可能是:

return equal(list1, list2, s -> s.length)
    && equal(list1, list2, Arrays::asList);

回答by khelwood

The forloop at least can be streamified, leading to:

for至少循环可以streamified,导致:

return (list1.size()==list2.size() &&
        IntStream.range(0, list1.size())
                 .allMatch(i -> Arrays.equals(list1.get(i), list2.get(i)));

回答by hahn

using zip(which originates from lambda b93) function from https://stackoverflow.com/a/23529010/755183, code could look like:

使用zip来自https://stackoverflow.com/a/23529010/755183 的(源自 lambda b93)函数,代码可能如下所示:

boolean match = a.size() == b.size() && 
                zip(a.stream(), b.stream(), Arrays::deepEquals).
                allMatch(equal -> equal)

update

更新

in order to check size of arrays first and then content this could be a solution to consider

为了首先检查数组的大小然后检查内容,这可能是一个需要考虑的解决方案

final boolean match = a.size() == b.size() 
                   && zip(a.stream(), b.stream(), (as, bs) -> as.length == bs.length).
                      allMatch(equal -> equal)
                   && zip(a.stream(), b.stream(), Arrays::deepEquals).
                      allMatch(equal -> equal);

回答by Alexis C.

You coulduse a stream if the lists are random access lists (so that a call to getis fast - generally constant time) leading to:

如果列表是随机访问列表(因此调用速度很快 - 通常是恒定时间),则您可以使用流get导致:

//checks for null and size before
boolean same = IntStream.range(0, list1.size()).allMatch(i -> Arrays.equals(list1.get(i), list2.get(i)));

However, you might give as parameters some implementations that are not (such as LinkedLists). In this case, the best way is to use the iterator explicitly. Something like:

但是,您可以将一些不是的实现(例如 LinkedLists)作为参数提供。在这种情况下,最好的方法是显式使用迭代器。就像是:

boolean compare(List<String[]> list1, List<String[]> list2) {

    //checks for null and size

    Iterator<String[]> iteList1 = list1.iterator();
    Iterator<String[]> iteList2 = list2.iterator();

    while(iteList1.hasNext()) {
        if(!Arrays.equals(iteList1.next(), iteList2.next())) {
            return false;
        }
    }
    return true;
}

回答by Federico Peralta Schaffner

You could stream over one list and compare to each element of the other by using an iterator:

您可以使用迭代器流式传输一个列表并与另一个列表的每个元素进行比较:

Iterator<String[]> it = list1.iterator();
boolean match = list1.size() == list2.size() &&
                list2.stream().allMatch(a -> Arrays.equals(a, it.next()));

Using an iterator instead of the get(index)method on the first list is better because it doesn't matter whether the list is RandomAccessor not.

使用迭代器而不是get(index)第一个列表上的方法更好,因为列表是否存在并不重要RandomAccess

Note: this only works with a sequentialstream. Using a parallel stream will lead to wrong results.

注意:这仅适用于顺序流。使用并行流将导致错误的结果。



EDIT: As per the question last edit, which indicates it would be better to check the length of every pair of arrays in advance, I think it could be achieved with a slight modification to my previous code:

编辑:根据问题的最后一次编辑,这表明这将是更好地检查每对数组的长度事先,我认为它可能有轻微的修改我以前的代码来实现:

Iterator<String[]> itLength = list1.iterator();
Iterator<String[]> itContents = list1.iterator();

boolean match = 
        list1.size() == list2.size()
    && 
        list2.stream()
            .allMatch(a -> {
                String[] s = itLength.next();
                return s == null ? a == null :
                       a == null ? s == null :
                       a.length == s.length;
            })
    && 
        list2.stream()
            .allMatch(a -> Arrays.equals(a, itContents.next()));

Here I'm using two iterators and am streaming list2twice, but I see no other way to check all lengths before checking the contents of the first pair of arrays. Check for lengths is null-safe, while check for contents is delegated to the Arrays.equals(array1, array2)method.

在这里,我使用了两个迭代器并且流式传输了list2两次,但是在检查第一对数组的内容之前,我看不到其他方法可以检查所有长度。检查长度是空安全的,而检查内容则委托给Arrays.equals(array1, array2)方法。