To be specific, I have two lists:
具体来说,我有两个清单:
List<SystemUserWithNameAndId> list1;
List<SystemUserWithNameAndId> list2;
I want to check if they contain the same system users and ordering is not an issue. I tried to use a comparator to sort them first and then check if they're equal using the equals() method of lists. But I don't want to override the equals method for SystemUserWithNameAndId and I was wondering if I could use the comparator I created for sorting or a similar one to check for equality without explicitly iterating through the lists after sorting.
我想检查它们是否包含相同的系统用户,并且订购不是问题。我尝试先使用比较器对它们进行排序,然后使用列表的equals()方法检查它们是否相等。但我不想覆盖SystemUserWithNameAndId的equals方法,我想知道我是否可以使用我为排序创建的比较器或类似的比较器来检查相等性,而不会在排序后显式迭代列表。
Comparator<SystemUserWithNameAndId> systemUserComparator = new Comparator<SystemUserWithNameAndId>()
{
@Override
public int compare(SystemUserWithNameAndId systemUser1, SystemUserWithNameAndId systemUser2)
{
final int systemUserId1 = systemUser1.getSystemUserId();
final int systemUserId2 = systemUser2.getSystemUserId();
return systemUserId1 == systemUserId2
? 0
: systemUserId1 - systemUserId2;
}
};
Collections.sort(systemUsers1, systemUserComparator);
Collections.sort(systemUsers2, systemUserComparator);
return systemUsers1.equals(systemUsers2);
Ideally, I want to be able to say,
理想情况下,我希望能够说,
CollectionUtils.isEqualCollections(systemUsers1, systemUsers2, someCustomComparator);
2 个解决方案
#1
Just implement the method that iterates, and reuse it every time you need it:
只需实现迭代的方法,并在每次需要时重用它:
public static <T> boolean areEqualIgnoringOrder(List<T> list1, List<T> list2, Comparator<? super T> comparator) {
// if not the same size, lists are not equal
if (list1.size() != list2.size()) {
return false;
}
// create sorted copies to avoid modifying the original lists
List<T> copy1 = new ArrayList<>(list1);
List<T> copy2 = new ArrayList<>(list2);
Collections.sort(copy1, comparator);
Collections.sort(copy2, comparator);
// iterate through the elements and compare them one by one using
// the provided comparator.
Iterator<T> it1 = copy1.iterator();
Iterator<T> it2 = copy2.iterator();
while (it1.hasNext()) {
T t1 = it1.next();
T t2 = it2.next();
if (comparator.compare(t1, t2) != 0) {
// as soon as a difference is found, stop looping
return false;
}
}
return true;
}
#2
Here's a Java 8 way of solving your problem. First make sure the lists are of equal length:
这是解决问题的Java 8方法。首先确保列表长度相等:
List<SystemUserWithNameAndId> list1 = ... ;
List<SystemUserWithNameAndId> list2 = ... ;
if (list1.size() != list2.size()) {
return false;
}
Now build a Comparator using the new comparator utilities. The idea is that instead of writing custom logic for a comparator, most comparators do something like comparing two objects by extracting a key from them, and then comparing the keys. That's what this does.
现在使用新的比较器实用程序构建Comparator。我们的想法是,大多数比较器不是为比较器编写自定义逻辑,而是通过从两个对象中提取密钥来比较两个对象,然后比较密钥。这就是它的作用。
Comparator<SystemUserWithNameAndId> comp =
Comparator.comparingInt(SystemUserWithNameAndId::getSystemUserId);
Sort the lists. Of course, you might want to make copies before sorting if you don't want your function to have the side effect of sorting its input. If your input lists aren't random access (who uses LinkedList
nowadays?) you might also want to copy them to ArrayList
s to facilitate random access.
对列表进行排序。当然,如果您不希望函数具有对其输入进行排序的副作用,您可能希望在排序之前制作副本。如果你的输入列表不是随机访问(谁现在使用LinkedList?),你可能还想将它们复制到ArrayLists以方便随机访问。
list1.sort(comp);
list2.sort(comp);
Run a stream over the indexes of the lists, calling the comparator on each pair. The comparator returns 0 if the elements are equals according to this comparator. If this is true for all pairs of elements, the lists are equal.
在列表的索引上运行流,在每对上调用比较器。如果元素根据此比较器等于,则比较器返回0。如果对于所有元素对都是如此,则列表是相等的。
return IntStream.range(0, list1.size())
.allMatch(i -> comp.compare(list1.get(i), list2.get(i)) == 0);
#1
Just implement the method that iterates, and reuse it every time you need it:
只需实现迭代的方法,并在每次需要时重用它:
public static <T> boolean areEqualIgnoringOrder(List<T> list1, List<T> list2, Comparator<? super T> comparator) {
// if not the same size, lists are not equal
if (list1.size() != list2.size()) {
return false;
}
// create sorted copies to avoid modifying the original lists
List<T> copy1 = new ArrayList<>(list1);
List<T> copy2 = new ArrayList<>(list2);
Collections.sort(copy1, comparator);
Collections.sort(copy2, comparator);
// iterate through the elements and compare them one by one using
// the provided comparator.
Iterator<T> it1 = copy1.iterator();
Iterator<T> it2 = copy2.iterator();
while (it1.hasNext()) {
T t1 = it1.next();
T t2 = it2.next();
if (comparator.compare(t1, t2) != 0) {
// as soon as a difference is found, stop looping
return false;
}
}
return true;
}
#2
Here's a Java 8 way of solving your problem. First make sure the lists are of equal length:
这是解决问题的Java 8方法。首先确保列表长度相等:
List<SystemUserWithNameAndId> list1 = ... ;
List<SystemUserWithNameAndId> list2 = ... ;
if (list1.size() != list2.size()) {
return false;
}
Now build a Comparator using the new comparator utilities. The idea is that instead of writing custom logic for a comparator, most comparators do something like comparing two objects by extracting a key from them, and then comparing the keys. That's what this does.
现在使用新的比较器实用程序构建Comparator。我们的想法是,大多数比较器不是为比较器编写自定义逻辑,而是通过从两个对象中提取密钥来比较两个对象,然后比较密钥。这就是它的作用。
Comparator<SystemUserWithNameAndId> comp =
Comparator.comparingInt(SystemUserWithNameAndId::getSystemUserId);
Sort the lists. Of course, you might want to make copies before sorting if you don't want your function to have the side effect of sorting its input. If your input lists aren't random access (who uses LinkedList
nowadays?) you might also want to copy them to ArrayList
s to facilitate random access.
对列表进行排序。当然,如果您不希望函数具有对其输入进行排序的副作用,您可能希望在排序之前制作副本。如果你的输入列表不是随机访问(谁现在使用LinkedList?),你可能还想将它们复制到ArrayLists以方便随机访问。
list1.sort(comp);
list2.sort(comp);
Run a stream over the indexes of the lists, calling the comparator on each pair. The comparator returns 0 if the elements are equals according to this comparator. If this is true for all pairs of elements, the lists are equal.
在列表的索引上运行流,在每对上调用比较器。如果元素根据此比较器等于,则比较器返回0。如果对于所有元素对都是如此,则列表是相等的。
return IntStream.range(0, list1.size())
.allMatch(i -> comp.compare(list1.get(i), list2.get(i)) == 0);