【问题标题】:Efficient way to Compare Two List's object values without implenmenting equals()?在不实现 equals() 的情况下比较两个 Lists 对象值的有效方法?
【发布时间】:2017-07-28 21:01:10
【问题描述】:

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

  1. Java Compare Two List's object values?
  2. Java ArrayList - how can I tell if two lists are equal, order not mattering?

但我的情况很烦人,让这个问题有点复杂。我需要比较的对象来自一个古老的第三方 jar,它没有 equals() 函数。而且我担心修改它的代码。

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

但我还是想知道有没有更好的办法?

【问题讨论】:

  • 我可能会为元素编写一个包含 equals() 的包装器并在列表中使用它们。
  • 你可以让另一个类负责计算相等性。使用方法如:public static boolean equalsAncientObj(Ancient a1, Ancient a2);。这需要公开公开足够有用的状态。然后你可以写一个“列表比较器”,它明确地使用这个函数来检查相等性。

标签: java list arraylist


【解决方案1】:

尝试使用 Apache Commons isEqualCollection(Collection a, Collection b, Equator equator),您仍然需要像编写 equals 覆盖一样实现 Equator。

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

【讨论】:

  • 正是我所需要的
【解决方案2】:

第 1 点:见 Kayaman 的评论(提供equals 函数的包装类)。

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

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

【讨论】:

    【解决方案3】:

    首先,您需要对象的行为良好的规范表示。 创建一个名为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()。

    【讨论】:

    • 当然它应该将 MyCustomObject 实例映射到该实例的出现次数,不是吗? (然后比较整个地图,而不仅仅是键集。)
    【解决方案4】:

    为了说明 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)));
    }
    

    如果没有匹配项,您会更快地中断,但可能会丢失有关潜在重复项的信息。

    【讨论】:

      【解决方案5】:

      我的方法也需要实现 equals 方法,但您不想在使用新字段更新对象时更新 equals 方法。

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

      【讨论】:

        猜你喜欢
        • 2016-05-25
        • 2018-04-28
        • 1970-01-01
        • 2011-04-26
        • 2012-01-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-23
        相关资源
        最近更新 更多