如何使用自定义比较器比较两个数组列表是否相等?
How can I compare two array lists for equality with a custom comparator?
具体来说,我有两个列表:
List<SystemUserWithNameAndId> list1;
List<SystemUserWithNameAndId> list2;
我想检查它们是否包含相同的系统用户并且排序不是问题。我尝试先使用比较器对它们进行排序,然后使用列表的 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);
理想情况下,我希望能够说,
CollectionUtils.isEqualCollections(systemUsers1, systemUsers2, someCustomComparator);
只需实现迭代的方法,并在每次需要时重用它:
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;
}
这里有 Java 8 种方法可以解决您的问题。首先确保列表的长度相等:
List<SystemUserWithNameAndId> list1 = ... ;
List<SystemUserWithNameAndId> list2 = ... ;
if (list1.size() != list2.size()) {
return false;
}
现在使用新的比较器实用程序构建一个比较器。这个想法是,大多数比较器不是为比较器编写自定义逻辑,而是通过从中提取键来比较两个对象,然后比较键。这就是它的作用。
Comparator<SystemUserWithNameAndId> comp =
Comparator.comparingInt(SystemUserWithNameAndId::getSystemUserId);
对列表进行排序。当然,如果您不希望您的函数产生对其输入进行排序的副作用,您可能希望在排序之前制作副本。如果您的输入列表不是随机访问的(现在谁使用 LinkedList
?)您可能还想将它们复制到 ArrayList
以方便随机访问。
list1.sort(comp);
list2.sort(comp);
运行 列表索引上的流,在每一对上调用比较器。比较器 returns 如果根据此比较器元素相等,则为 0。如果所有元素对都是如此,则列表相等。
return IntStream.range(0, list1.size())
.allMatch(i -> comp.compare(list1.get(i), list2.get(i)) == 0);
具体来说,我有两个列表:
List<SystemUserWithNameAndId> list1;
List<SystemUserWithNameAndId> list2;
我想检查它们是否包含相同的系统用户并且排序不是问题。我尝试先使用比较器对它们进行排序,然后使用列表的 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);
理想情况下,我希望能够说,
CollectionUtils.isEqualCollections(systemUsers1, systemUsers2, someCustomComparator);
只需实现迭代的方法,并在每次需要时重用它:
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;
}
这里有 Java 8 种方法可以解决您的问题。首先确保列表的长度相等:
List<SystemUserWithNameAndId> list1 = ... ;
List<SystemUserWithNameAndId> list2 = ... ;
if (list1.size() != list2.size()) {
return false;
}
现在使用新的比较器实用程序构建一个比较器。这个想法是,大多数比较器不是为比较器编写自定义逻辑,而是通过从中提取键来比较两个对象,然后比较键。这就是它的作用。
Comparator<SystemUserWithNameAndId> comp =
Comparator.comparingInt(SystemUserWithNameAndId::getSystemUserId);
对列表进行排序。当然,如果您不希望您的函数产生对其输入进行排序的副作用,您可能希望在排序之前制作副本。如果您的输入列表不是随机访问的(现在谁使用 LinkedList
?)您可能还想将它们复制到 ArrayList
以方便随机访问。
list1.sort(comp);
list2.sort(comp);
运行 列表索引上的流,在每一对上调用比较器。比较器 returns 如果根据此比较器元素相等,则为 0。如果所有元素对都是如此,则列表相等。
return IntStream.range(0, list1.size())
.allMatch(i -> comp.compare(list1.get(i), list2.get(i)) == 0);