比较两个List的对象值而不实现equals()的有效方法?

时间:2017-03-08 10:32:28

标签: java list arraylist

我在这里有两个类似的问题:

  1. Java Compare Two List's object values?
  2. Java ArrayList - how can I tell if two lists are equal, order not mattering?
  3. 但我有一个很糟糕的情况,这个问题有点复杂。我需要比较的对象来自一个古老的第三方jar,它没有equals()函数。我担心修改它的代码。

    我提出的一个解决方案是构建另外两个列表,它们的值是原始列表的串联。问题与问题2没有区别。

    但我仍然想知道是否有更好的方法?

5 个答案:

答案 0 :(得分:3)

尝试使用Apache Commons isEqualCollection(Collection a, Collection b, Equator equator),您仍然需要以与编写equals覆盖相同的方式实现Equator。

您也可以尝试this one,这与Apache Commons的算法相同,但有一些性能改进。

答案 1 :(得分:0)

第1点:参见Kayaman的评论(提供equals功能的包装类)。

第2点:此包装类可能另外提供lessThan函数,对元素强加绝对顺序。然后,您可以对两个列表进行排序,然后逐个元素地进行比较。这比尝试识别另一个列表中每个元素的每个元素更有效,并且还可以优雅地处理重复的问题。

e的实施例。 G。快速排序可以在互联网上找到,例如。 G。 here

答案 2 :(得分:0)

首先,您需要一个表现良好的对象规范表示。 创建一个名为MyCustomObject的类(希望你能想到一个更好的名字),它包含原始对象中最相关的属性,并实现equals(),hashCode()和toString()。编写一个构造函数或工厂方法,从原始对象创建MyCustomObject实例。现在将您的列表转换为地图:

List<OriginalObject> list = // wherever you get your list from
Map<MyCustomObject> map = list.stream()
                              .collect(
                                 Collectors.toMap(
                                    MyCustomObject::new,
                                    (oo)->oo)
                               );

对两个列表执行此操作,并比较两个映射的keySet()。

答案 3 :(得分:0)

为了说明Kayaman的答案,您可以执行以下操作:

public class EqualsWrapper {
    private final Object delegate;

    public EqualsWrapper(Object toWrap) {
        delegate = toWrap;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((delegate == null) ? 0 : delegate.toString().hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        EqualsWrapper other = (EqualsWrapper) obj;
        return other.toString().equals(obj.toString());
    }
}

public static boolean areListsEqual(List list1, List list2){
    Set<EqualsWrapper> l_set1 = list1.stream().map(e -> new EqualsWrapper(e)).collect(Collectors.toSet());
    Set<EqualsWrapper> l_set2 = list2.stream().map(e -> new EqualsWrapper(e)).collect(Collectors.toSet());

    return l_set1.equals(l_set2);
}

然而,如果您有非常大的列表并且很有可能它们不相等,那么复制整个列表可能不是最佳选择。 你也可以遵循这个立场:

public static boolean areListsEqual(List list1, List list2){
    return list1.stream().map(e -> new EqualsWrapper(e)).allMatch(e -> list2.stream().map(e -> new EqualsWrapper(e)).anyMatch(e2 -> e2.equals(e)));
}

如果没有匹配但您可能会在没有匹配的情况下更快地破解,但是可能会丢失有关潜在重复项的信息。

答案 4 :(得分:0)

我的方法还需要实现equals方法,但是每当使用新字段更新对象时,您都不希望更新equals方法。

Try it out,我相信,这种方法可以接受。

相关问题