【问题标题】:What is the best way to compare two objects having multiple list attributes比较具有多个列表属性的两个对象的最佳方法是什么
【发布时间】:2019-11-28 12:30:57
【问题描述】:

我有一个具有多个列表属性的 POJO/DTO 类,例如

class Boo {    
    private List<Foo> foos;
    private List<Integer> pointers;
}

我想比较两个列表是否包含相同的值而忽略列表的顺序。是否可以在不打开对象和排序列表的情况下实现这一点?

我们将不胜感激。提前致谢

【问题讨论】:

  • 它们如何包含相同的值? FooInteger 吗?
  • opening 对象是什么意思?另外,如果没关系,您为什么要订购清单?
  • 我认为 OP 想要比较两个 List&lt;Boo&gt;,这也包括比较它们的类属性。或者只是比较Boo 的两个实例。
  • 你可以使用集合。比较大小,如果a.containsAll(b),则两组相等。
  • 好吧,无论如何,比较都归结为equals 实现。这是一个非常广泛的问题,必须更多地发现问题才能确定解决方法

标签: java list comparator comparable


【解决方案1】:

这归结为比较列表。如果项目的顺序无论如何都无关紧要,那么使用Set 而不是List 可能会更好。

你的 equals 看起来像

public boolean equals(object other) {
    //here be class and null checks
    return foos.equals(other.foos) && pointers.equals(other.pointers);
}

如果您不能使用 Set - 因为您可以多次拥有相同的项目或因为订单很重要 - 您可以通过互惠的containsAll() 调用执行与上述相同的操作。这仍然不会考虑重复条目,但否则会很好。

您声明您无法编辑课程Boo。一种解决方案是创建一个类似于Objects.equals() 的服务类。

class BooComparer {

    public static bool equals(Boo a, Boo b) {
        //again do some null checks here
        return a.foos.containsAll(b.foos) 
          && b.foos.containsAll(a.foos)
          && a.pointers.containsAll(b.pointers)
          && b.pointers.containsAll(a.pointers)
    }
}

如果这对你有用 - 很好。也许你也必须比较其他成员。再说一遍:如果其中一个列表有两次条目,这将忽略。

【讨论】:

  • 正确我同意你的看法。我的双手被绑住了。不能换班。它是根据 api 规范。
  • @deepesh 无法更改哪个类?
  • 如果你不能实现类的等号,你必须实现像Objects.equals()这样的外部比较。我会相应地更新我的答案。
【解决方案2】:

“我想比较两者是否包含相同的值而不是列表的顺序。”

没有一个通用的相等运算符。有时您想按某些属性比较对象。典型的例子可能是比较字符串,有时“computer”等于或不等于“Computer”或“Vesterålen”等于或不等于“Vesteralen”。

Java中,您可以重新定义对象之间的default等价关系(修改默认行为!)。

对象List 使用包含对象的默认等价关系作为默认等价关系并按顺序检查该等价关系。

以下示例仅忽略一个属性中的元素顺序:

class My {
    private final List<String> xs;
    private final List<Integer> ys;

    My(List<String> xs, List<Integer> ys) {
        this.xs = xs;
        this.ys = ys;
    }

    public List<Integer> getYs() {
        return ys;
    }

    public List<String> getXs() {
        return xs;
    }

    @Override
    public int hashCode() {
        return xs.hashCode() + 7 * ys.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if(!(obj instanceof My))
            return false;
        My o = (My) obj;
        return
                // ignoring order
                getXs().stream().sorted().collect(toList()).equals(o.getXs().stream().sorted().collect(toList()))
                // checking order
                && getYs().equals(o.getYs());
    }
}

public class Callme {
    public static void main(String... args) {
        My m1 = new My(asList("a", "b"), asList(1, 2));
        My m2 = new My(asList("b", "a"), asList(1, 2));
        My m3 = new My(asList("a", "b"), asList(2, 1));
        System.out.println(m1.equals(m2));
        System.out.println(m1.equals(m3));
    }
}

有输出

true
false

但是我无法定义您所需的等价关系,例如,如果一个列表包含的元素比另一个列表多,但也许您希望(例如,对您来说等于 {a, b, a}{b, a})。

因此,为您的对象定义等价关系并覆盖 hashCodeequals

【讨论】:

  • 这可以做到,不能改变集合但当然可以实现equals
  • @deepeshkumar 我不明白你。是的,你必须定义你想要什么等价关系,然后覆盖hashCodeequals(我的代码就是一个例子)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-14
  • 2015-08-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多