Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Test if two sets share 3 elements with Java streams

I need a Java stream operation to test if two sets have at least 3 common elements.

Here is my Java 7 code that works fine:

@Test
public void testContainement(){
    Set<Integer> setOne = IntStream.of(0,1,4,3)
                                   .boxed()
                                   .collect(Collectors.toCollection(HashSet::new));

    Set<Integer> setTwo = IntStream.of(0,1,4,5)
            .boxed()
            .collect(Collectors.toCollection(HashSet::new));

    Assertions.assertEquals(true,testSets(setOne,setTwo));

}

private boolean testSets( Set<Integer> setOne, Set<Integer> setTwo ) {
    int counter=0;
    for (int x: setOne){
        if (setTwo.contains(x))
            counter++;
    }
    return counter > 2;
}

How can we do that with Java stream operations?

like image 860
xmen-5 Avatar asked May 14 '19 14:05

xmen-5


People also ask

How do you check if a stream contains a specific element?

Java Stream anyMatch () Examples Example 1: Java program to check if stream contains a specific element In this Java example, we are using the anyMatch () method to check if the stream contains the string "four". As we see that the stream contains the string, so the output of the example is true.

How to compare two sets in Java to check equality?

We often need to compare two sets to check whether they contain the same elements or not, and both sets should also have the same size. The Set interface provides the equals () method for verifying the equality of the given two sets. It returns either true or false based on the equality of both sets.

How do I concatenate two streams in Java?

Stream.concat () method creates a lazily concatenated stream whose elements are all the elements of the first stream followed by all the elements of the second stream. import java.util.stream.*; Set a: [1, 3, 5, 7, 9] Set b: [0, 2, 4, 6, 8] Merged Set: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

How to add multiple conditions to stream objects in Java?

You can use predicate or () or isEquals () methods with the multiple predicate conditions. 4. Conclusion You learned how to use the filter () method and the predicate and () method to add multiple conditions to stream objects in this article.


3 Answers

You could use simply Set.retainAll(Collection) :

setOne.retainAll(setTwo);
boolean isMoreTwo = setOne.size() > 2

If you don't want to modify setOne, create a new instance of the Set :

Set<Integer> newSetOne = new HashSet<>(setOne)
newSetOne.retainAll(setTwo);
boolean isMoreTwo = newSetOne.size() > 2

Note that all ways actually shown to solve your need (in your question, my answer and that one of Naman) are not correct way to perform an assertion in an unit test.
An assertion should produce a useful error message if the assertion fails.
So that will really not help you since a boolean is true or false and that's all :

Assertions.assertEquals(true,testSets(setOne,setTwo));

Besides, it should also be written rather like :

Assertions.assertTrue(testSets(setOne,setTwo));

To achieve your requirement, you should count the number of matching elements between the sets and stopping it as soon as you reach the desired target.

long nbMatchLimitedToThree = setOne.stream().filter(setTwo::contains).limit(3).count();
Assertions.assertEqual(3, nbMatchLimitedToThree, "At least 3 matches expected but actually only " +  nbMatchLimitedToThree +". setOne=" + setOne + ",setTwo=" + setTwo);  

That is more performant and that is a correct way to write unit tests.

like image 57
davidxxx Avatar answered Oct 19 '22 14:10

davidxxx


Use Stream.count as

private boolean testSets(Set<Integer> setOne, Set<Integer> setTwo) {
    return setOne.stream().filter(setTwo::contains).count() > 2;
}

or to add to it, avoiding to iterate through the complete set if more than two elements are found early, use limit as:

return setOne.stream().filter(setTwo::contains).limit(3).count() > 2;
like image 36
Naman Avatar answered Oct 19 '22 13:10

Naman


guava makes this very easy to read:

private boolean testSets( Set<Integer> setOne, Set<Integer> setTwo ) {
     return Sets.intersection(setOne, setTwo).size() > 2;
}
like image 39
Eugene Avatar answered Oct 19 '22 14:10

Eugene