如何比较数组列表与现代Java的平等?
我有两个数组列表。
如何轻松比较这些与Java 8及其function的平等,而不使用外部库? 我正在寻找比这样的暴力代码更好的(更高级的,更短的,更高效的)解决scheme(未经testing的代码,可能包含错别字等,而不是问题的要点):
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; }
或者,如果没有更好的方法,那也是一个有效的答案。
奖金:如果Java 9提供更好的Java 8可以提供的更好的方式,请随时提及它。
编辑:在看了这些注释之后,看看这个问题是如何变得温和的,我认为“ 更好 ”应该包括在检查数组内容之前首先检查所有数组的长度 ,因为如果内部的内部有潜在的不平等数组很长。
1)基于Java 8stream的解决scheme:
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)更简单的解决scheme(适用于Java 5+):
return Arrays.deepEquals(list1.toArray(), list2.toArray());
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); }
那么解决scheme可能是:
return equal(list1, list2, s -> s.length) && equal(list1, list2, Arrays::asList);
for
循环至less可以stream水化,导致:
return (list1.size()==list2.size() && IntStream.range(0, list1.size()) .allMatch(i -> Arrays.equals(list1.get(i), list2.get(i)));
从https://stackoverflow.com/a/23529010/755183使用;zip
(源自lambda b93)函数,代码可能如下所示:
boolean match = a.size() == b.size() && zip(a.stream(), b.stream(), Arrays::deepEquals). allMatch(equal -> equal)
更新
为了首先检查数组的大小,然后再考虑内容,这可能是一个需要考虑的解决scheme
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);
如果列表是随机访问列表,那么你可以使用一个stream(这样调用get
的速度就快了 – 通常是不变的),这导致:
//checks for null and size before boolean same = IntStream.range(0, list1.size()).allMatch(i -> Arrays.equals(list1.get(i), list2.get(i)));
但是,您可能会给出一些不是的实现(如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; }
您可以通过使用迭代器来对一个列表进行stream式处理,并与另一个列表的每个元素进行比较:
Iterator<String[]> it = list1.iterator(); boolean match = list1.size() == list2.size() && list2.stream().allMatch(a -> Arrays.equals(a, it.next()));
在第一个列表中使用迭代器而不是get(index)
方法更好,因为列表是否是RandomAccess
并不重要。
注意:这只适用于顺序stream。 使用并行stream将导致错误的结果。
编辑:根据最后编辑的问题,这表明最好检查每一对arrays的长度提前 ,我认为可以实现对我以前的代码略作修改:
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()));
在这里,我使用了两个迭代器,并且是stream式处理list2
两次,但是在检查第一对数组的内容之前我没有其他办法检查所有的长度。 检查长度是否为空安全的,而检查内容是否委托给Arrays.equals(array1, array2)
方法。