[英]How to compare equality of lists of arrays with modern Java?
I have two lists of arrays. 我有两个数组列表。
How do I easily compare equality of these with Java 8 and its features , without using external libraries? 如何在不使用外部库的情况下轻松地将这些与Java 8及其功能的相等性进行比较? 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):
我正在寻找一个“更好”(更高级别,更短,更高效)的解决方案,而不是像这样的强力代码(未经测试的代码,可能包含错别字等,而不是问题的重点):
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. 编辑:看完评论,看看这个问题是如何变得适度热,我认为“ 更好 ”应该包括在检查数组内容之前首先检查所有数组的长度 ,因为这有可能更快地找到不等式,如果内部数组很长。
The for
loop at least can be streamified, leading to: for
循环至少可以流式化,导致:
return (list1.size()==list2.size() &&
IntStream.range(0, list1.size())
.allMatch(i -> Arrays.equals(list1.get(i), list2.get(i)));
using zip
(which originates from lambda b93) function from https://stackoverflow.com/a/23529010/755183 , code could look like: 使用
zip
(源自lambda b93)函数来自https://stackoverflow.com/a/23529010/755183 ,代码可能如下所示:
boolean match = a.size() == b.size() &&
zip(a.stream(), b.stream(), Arrays::deepEquals).
allMatch(equal -> equal)
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);
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)关于您的新要求(首先检查包含的String数组长度),您可以编写一个通用的帮助器方法,对转换后的列表进行相等性检查:
<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);
You could use a stream if the lists are random access lists (so that a call to get
is 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). 但是,您可以为某些非实现的实现(例如LinkedLists)提供参数。 In this case, the best way is to use the iterator explicitly.
在这种情况下,最好的方法是显式使用迭代器。 Something like:
就像是:
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;
}
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 RandomAccess
or not. 在第一个列表中使用迭代器而不是
get(index)
方法更好,因为列表是否为RandomAccess
无关紧要。
Note: this only works with a sequential stream. 注意:这仅适用于顺序流。 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 list2
twice, but I see no other way to check all lengths before checking the contents of the first pair of arrays. 这里我使用两个迭代器并且两次流式传输
list2
,但在检查第一对数组的内容之前,我没有看到检查所有长度的其他方法。 Check for lengths is null-safe, while check for contents is delegated to the Arrays.equals(array1, array2)
method. 检查长度是否为空安全,而检查内容是否委托给
Arrays.equals(array1, array2)
方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.