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

对着背影说爱祢 提交于 2019-12-12 10:54:46

问题


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.

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

回答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:

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 LinkedList nowadays?) you might also want to copy them to ArrayLists to facilitate random access.

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.

return IntStream.range(0, list1.size())
    .allMatch(i -> comp.compare(list1.get(i), list2.get(i)) == 0);


来源:https://stackoverflow.com/questions/30106376/how-can-i-compare-two-array-lists-for-equality-with-a-custom-comparator

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!