Как с помощью одного стрима выполнить 2 условия, первое из которых требует проверки по всему стриму?
У меня есть коллекция чисел, и, если она содержит числа кратные 3, я вывожу на экран только их, а если нет - то числа, кратные пяти. Я могу сделать это так, но есть ли способ сделать это действие внутри одного стрима?
if (numbers.stream()
.filter(el -> el % 3 == 0)
.count() > 0) {
numbers = numbers.stream().
filter(el -> el % 3 == 0)
.collect(Collectors.toList());
} else {
numbers = numbers.stream()
.filter(el -> el % 5 == 0)
.collect(Collectors.toList());
}
Ответы (5 шт):
Может что-то в этом духе (могла попутать функции но смысл остается)
Function<List<Integer>, Predicate<Integer>> func = list - > {
return list.stream().anyMatch(el -> el % 3 == 0) ?
el - > el % 3 == 0 : el - > el % 5 == 0;
}
numbers.stream()
.filter(number - > func.apply(numbers).test(number))
.forEach(System.out::println);
Решил так:
numbers = numbers.stream()
.filter(numbers.stream()
.anyMatch(el -> el % 3 == 0)
? el -> el % 3 == 0 : el -> el % 5 == 0)
.collect(Collectors.toList());
Типо так (вариант #2)
Function<List<Integer>, Predicate<Integer>> func = list - > {
return list.stream().anyMatch(el -> el % 3 == 0) ?
el - > el % 3 == 0 : el - > el % 5 == 0;
}
Predicate<Integer> predicate = func.apply(numbers);
numbers.stream()
.filter(predicate::test)
.forEach(System.out::println);
Более корректное решение внутри одного стрима: накопить подходящие кратные числа в разных списках, и если список кратных тройке непустой, выводить его, иначе выводить список кратных пятерке:
List<Integer> filtered = numbers.stream()
.filter(x -> x % 3 == 0 || x % 5 == 0)
.collect(Collectors.collectingAndThen(
Collectors.partitioningBy(x -> x % 3 == 0),
(map) -> map.get(true).isEmpty() ? map.get(false) : map.get(true)
));
System.out.println(filtered);
Другие Предыдущие предложенные решения использовали два прохождения по стриму в худшем случае.
Также решение в один проход. Суть его в групировке значений по делимости на 3 и 5 в сортированную хеш таблицу.
numbers.stream().filter(x -> x % 3 == 0 || x % 5 == 0)
.collect(Collectors.groupingBy(x -> x % 3 == 0 ? 1 : 2,
() -> new TreeMap<>(), Collectors.toList()))
.firstEntry()
.getValue()
.forEach(System.out::println);
На случай, если в исходных данных нет значений, которые бы делились на 3 или 5, то можно заранее предусмотреть пустой вывод. Код наверняка можно изящней переписать, но как умею )
TreeMap<Integer, List<Integer>> map = new TreeMap<>();
map.put(Integer.MAX_VALUE, new ArrayList<>());
numbers.stream().filter(x -> x % 3 == 0 || x % 5 == 0)
.collect(Collectors.groupingBy(x -> x % 3 == 0 ? 1 : 2,
() -> map, Collectors.toList()))
.firstEntry()
.getValue()
.forEach(System.out::println);