1

What is the best way to compares the items of two lists by (only) some of their properties?

public class A {
    private String type;
    private String value;
    private String foo;
    private String bar;
}

List<A> listA = List.of(...);
List<A> listB = List.of(...);

I tried

return listA.stream().anyMatch( a -> listB.stream().anyMatch(b -> {
    a.getType().equals(b.getType());
    a.getValue().equals(b.getValue());}
));

...but this doesn't work.

It would be sufficient to find any/the first match and return true then or false if no match can be found.

Update / Example


A a1 = new A();
a1.setType("AB");
a1.setValue("xx");

A a2 = new A();
a2.setType("XY");
a2.setValue("00");

List<A> listA = List.of(a1, a2);

A b1 = new A();
b1.setType("AB");
b1.setValue("xx");

A b2 = new A();
b2.setType("XY");
b2.setValue("");

List<A> listB = List.of(b1, b2);

Using these lists in (with compVal = listA and expVal = listB):

public static boolean isValid(final List<A> compAs, final List<A> expAs) {
    
    return compAs.stream().anyMatch(a -> expAs.stream().anyMatch(e -> {
    return c.getType().equals(e.getType()) &&
                c.getValue().equals(e.getValue())
    }
} 

an assertFalse(isValid()) test fails (returns true while false is expected).

I tried with

return e.equals(c)

as well.

Using allMatch() ends up in a failure if the list are really equal.

du-it
  • 2,561
  • 8
  • 42
  • 80
  • what exactly do you want as result? a List containing the matches? "this doesn't work", can you be more clear on that part? does it give an error? does it return different results compared to what you want? – Stultuske Jan 06 '22 at 08:13
  • 1
    @Stultuske `It would be sufficient to find any/the first match and return true then or false if no match can be found.` – Eran Jan 06 '22 at 08:15

1 Answers1

1

If you want both properties to match, it should be:

return listA.stream()
            .anyMatch( a -> listB.stream()
                                 .anyMatch(b -> a.getType().equals(b.getType()) &&
                                                a.getValue().equals(b.getValue())));

This will compare all pairs of elements of the two lists until a match is found.

EDIT:

If you require that each element of the first List have a matching element of the second List, use allMatch in the outer Stream:

return listA.stream()
            .allMatch( a -> listB.stream()
                                 .anyMatch(b -> a.getType().equals(b.getType()) &&
                                                a.getValue().equals(b.getValue())));
Eran
  • 387,369
  • 54
  • 702
  • 768
  • It was just the '&&'? LOL – du-it Jan 06 '22 at 09:02
  • @du-it not just the `&&`. The body block of your lambda expression had no return statement. – Eran Jan 06 '22 at 09:06
  • Look at what I tried: return listA.stream()... So...I had a return statement. – du-it Jan 06 '22 at 09:12
  • @du-it I was referring to this block: `{ a.getType().equals(b.getType()); a.getValue().equals(b.getValue());}` which had no return statement. – Eran Jan 06 '22 at 09:13
  • Well, okay, ...but in your suggestion there is no return statement as well!?! (I added it by myself because IntelliJ complained. ;-) ) – du-it Jan 06 '22 at 09:39
  • 1
    @du-it lambda expression body can be either an expression or a block. An expression (as in my answer) doesn't require a return statement. A block (`{...}`), as in your question, requires a return statement (assuming the lambda expression's method has a non-void return type). – Eran Jan 06 '22 at 09:46
  • Thank you!!! Now I see the difference. :-) – du-it Jan 06 '22 at 09:47
  • I tested around and it seems as if the solution is not quite correct. I updated my question. – du-it Jan 06 '22 at 11:21
  • @du-it why do you expect `false` to be returned in the example you added? Earlier you wrote that true should be returned if any match is found. – Eran Jan 06 '22 at 11:46
  • I have to apologize!!! I need to compare EACH item. Like two nested for loops. – du-it Jan 06 '22 at 12:12
  • @du-it in that case, I believe you should change the first (outer) `anyMatch` to `allMatch`. – Eran Jan 06 '22 at 12:13