Проверьте, если два набора совместно используют 3 элемента с потоками Java - PullRequest
10 голосов
/ 14 мая 2019

Мне нужна операция потока Java, чтобы проверить, имеют ли два набора хотя бы 3 общих элемента.

Вот мой код Java 7, который отлично работает:

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

Как мы можем это сделатьчто с операциями потока Java?

Ответы [ 3 ]

11 голосов
/ 14 мая 2019

Вы можете просто использовать Set.retainAll(Collection):

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

Если вы не хотите изменять setOne, создайте новый экземпляр набора:

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

Обратите внимание, что все способы, показанные для решения вашей задачи (в вашем вопросе, моем ответе и ответе Намана), не являются правильным способом выполнения утверждения в модульном тесте.
Утверждение должно выдавать полезное сообщение об ошибке, еслиутверждение не выполняется.
Так что это действительно не поможет, так как логическое значение истинно или ложно, и это все:

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

Кроме того, оно также должно быть написано скорее как:

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

Чтобы выполнить ваше требование, вы должны посчитать количество подходящих элементов между наборами и остановить его, как только вы достигнете желаемой цели.

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

Это более производительный и правильный способ написания модульных тестов.

6 голосов
/ 14 мая 2019

Используйте Stream.count как

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

или для добавления к нему, избегая итерации по всему набору, если более двух элементов обнаружены ранее, используйте limit как:

return setOne.stream().filter(setTwo::contains).limit(3).count() > 2;
3 голосов
/ 15 мая 2019

Гуава делает это очень легко читать:

private boolean testSets( Set<Integer> setOne, Set<Integer> setTwo ) {
     return Sets.intersection(setOne, setTwo).size() > 2;
}
...