Разделить поток означает поместить каждый элемент в одну из двух групп.Поскольку у вас есть больше суффиксов, вместо этого вы хотите группировка , т.е. использовать groupingBy
вместо partitioningBy
.
Если вы хотите поддерживать произвольный список endings
, вы можете предпочесть что-толучше, чем линейный поиск.
Один из подходов - использование отсортированной коллекции с использованием компаратора на основе суффикса.
Компаратор может быть реализован как
Comparator<String> backwards = (s1, s2) -> {
for(int p1 = s1.length(), p2 = s2.length(); p1 > 0 && p2 > 0;) {
int c = Integer.compare(s1.charAt(--p1), s2.charAt(--p2));
if(c != 0) return c;
}
return Integer.compare(s1.length(), s2.length());
};
Логикапохож на естественный порядок строк, с той лишь разницей, что он проходит от конца к началу.Другими словами, это эквивалентно Comparator.comparing(s -> new StringBuilder(s).reverse().toString())
, но более эффективно.
Затем, учитывая такой ввод, как
List<String> endings= Arrays.asList("AAA", "BBB", "CCC", "DDD");
List<String> fullList= Arrays.asList("111.AAA", "222.AAA",
"111.BBB", "222.BBB", "111.CCC", "222.CCC", "111.DDD", "222.DDD");
, вы можете выполнить задачу как
// prepare collection with faster lookup
TreeSet<String> suffixes = new TreeSet<>(backwards);
suffixes.addAll(endings);
// use it for grouping
Map<String, List<String>> map = fullList.stream()
.collect(Collectors.groupingBy(suffixes::floor));
Но если вас интересует только количество каждой группы, при группировке вы должны считать правильно, избегая хранения списков элементов:
Map<String, Long> map = fullList.stream()
.collect(Collectors.groupingBy(suffixes::floor, Collectors.counting()));
Если список может содержать строки, которые не соответствуют суффиксу списка, вы должны заменить suffixes::floor
на s -> { String g = suffixes.floor(s); return g!=null && s.endsWith(g)? g: "_None"; }
или аналогичную функцию.