Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparing two collections using Stream - anyMatch

I want to compare if any of the objects in a list2 is present in a list1.

I could iterate over both lists and compare all elements using .contains() but I am wondering if there is not a more efficient way. I found this and I am trying to implement the suggested method:

List<Item> list1;
List<Item> list2;

boolean anyMatch = list1.stream().anyMatch(x -> x.equals(list2.stream()));
System.out.println(anyMatch);

When I do this I constantly get false, even when I'd expect a true. How come?

like image 532
k88 Avatar asked Apr 16 '16 22:04

k88


People also ask

What is the difference between the anyMatch () and findAny () stream methods?

They do the same job internally, but their return value is different. Stream#anyMatch() returns a boolean while Stream#findAny() returns an object which matches the predicate.

What is the difference between collections and stream?

Streams are not modifiable i.e one can't add or remove elements from streams. These are modifiable i.e one can easily add to or remove elements from collections. Streams are iterated internally by just mentioning the operations. Collections are iterated externally using loops.

How do you compare a field between two lists of objects?

Java equals() method This method accepts an object to be compared for equality with the list. It returns true if the specified object is equal to the list, else returns false. In the following example, we have create two ArrayList firstList and secondList. Comparing both list by using equals() method, it returns true.

What is the use of anyMatch in Java?

Stream anyMatch() in Java with examples Stream anyMatch(Predicate predicate) returns whether any elements of this stream match the provided predicate. It may not evaluate the predicate on all elements if not necessary for determining the result. This is a short-circuiting terminal operation.


2 Answers

From your comments, you have two lists, list1 and list2. You want to find out if at least one of the element in list2 is contained in list1.

With the Stream API, you can acquire a Stream of list2. Then, a call anyMatch(predicate) returns whether one of the element of this stream matches the given predicate, which, in this case, tests whether the element is contained in list1.

boolean anyMatch = list2.stream().anyMatch(list1::contains);

This uses a method reference as the predicate.

You would have better performance by converting the list1 into a Set, which guarantees constant-time look-up:

boolean anyMatch = list2.stream().anyMatch(new HashSet<>(list1)::contains);
like image 192
Tunaki Avatar answered Oct 04 '22 23:10

Tunaki


Although @Tunaki's answer is correct, here's another more concise way (it doesn't use Stream.anyMatch() method, though):

boolean anyMatch = !Collections.disjoint(list1, list2);

This uses the Collections.disjoint() method, which returns true when two collections have no elements in common.

Tunaki's comment regarding performance also applies here: for better performance, the best would be to turn your list1 into a HashSet, because its contains() method is O(1) average. The Collections.disjoint() method actually checks if any of its arguments is a Set and iterates over the collection that is not a Set. So in your case, all you have to do is create a HashSet from your list1:

boolean anyMatch = !Collections.disjoint(new HashSet<>(list1), list2);

Note: After all, my answer is only 5 characters shorter that Tunaki's :)

like image 43
fps Avatar answered Oct 04 '22 21:10

fps