java 如何使用自定义比较器比较两个数组列表的相等性?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30106376/
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-02 16:29:21  来源:igfitidea点击:

How can I compare two array lists for equality with a custom comparator?

javagenericscollectionscomparison

提问by Bruce Wayne

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);

回答by JB Nizet

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;
}

回答by Stuart Marks

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<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 LinkedListnowadays?) you might also want to copy them to ArrayLists 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);