简体   繁体   中英

What is the best way to compare two objects having multiple list attributes

I have a POJO/DTO class with multiple list attribute like

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

I want to compare if both lists contain the same values ignoring the order of the lists. Is it possible to achieve this without opening the object and ordering the lists?

Help would be appreciated. Thanks in Advance

"I want to compare if both contains same values instead of the order of list."

There is not a universal equality operator. Sometimes you want compare objects by certain properties. Probably the canonical example could be comparing strings, sometimes "computer" is equal or not than "Computer" or "Vesterålen" is equal or not than "Vesteralen".

In Java , you can redefine the default equivalence relation between objects (modifying the default behavior!).

The object List use as default equivalence relation the default equivalence relation of the contained objects and checking that equality in order.

The following example ignore the elements order only in one property:

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

with output

true
false

But I can't define YOUR required equivalence relation , for example I do not ignore if one list contains more elements than the other but maybe you wish (eg. to you is equal {a, b, a} than {b, a} ).

So, define you equivalence relation for your object and override hashCode and equals .

This boils down to comparing the lists. If the order of the items is irrelevant anyways you might fare better using Set instead of List .

Your equals then would look like

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

If you cannot use Set - either because you can have the same item multiple times or because order matters - you have can do the same as above with a reciprocal containsAll() call. This still would not take duplicate entries into consideration but will work quite fine otherwise.

You state that you cannot edit the class Boo . One solution would be to have a service class which does this for you a bit similar to 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)
    }
}

If this works for you - fine. Maybe you have to compare other members, too. And again: this will ignore if one of the lists has an entry twice.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM