Учитывая список строк, возможно ли получить в одной строке сопоставление каждой длины с набором строк этой длины, отсортированных по длине?
Я придумал следующее, которое действительно работает, но я чувствую, что должен быть более чистый однострочный способ, который не полагается на "внешнюю" карту (result
ниже):
public TreeMap<Integer, HashSet<String>> mapLenToString(List<String> strings){
TreeMap<Integer, HashSet<String>> result = new TreeMap<>();
strings.stream()
.forEach(s -> {
int len = s.length();
if (result.containsKey(len)) {
HashSet<String> larger = result.get(len);
larger.add(s);
result.replace(len, larger);
}
else {
HashSet<String> newSet = new HashSet<>();
newSet.add(s);
result.put(len, newSet);
}
});
return result;
}
2 ответа
Решение
Просто используйте groupingBy
коллектор. Вы можете управлять типом карты и типом набора, в который собираются элементы.
TreeMap<Integer, HashSet<String>> result = strs
.stream()
.collect(
Collectors.groupingBy(
s -> s.length(),
TreeMap::new,
Collectors.toCollection(HashSet::new)
)
);
Используя это
List<String> strs = Arrays.asList(
"DEF", "ABC", "Hello world", "z",
"a", "q", "90", "12345678910", "ab");
выход
{1=[a, q, z], 2=[90, ab], 3=[ABC, DEF], 11=[12345678910, Hello world]}
Вы также можете использовать Collectors.toSet()
вместо того toCollection(HashSet::new)
, где реализация по умолчанию HashSet
(но, вероятно, не гарантируется)
Альтернатива с использованием Guava Multimaps:com.google.common.collect.Multimaps.index (итерация, функция)-
Multimap<Integer, String> index =
Multimaps.index(strs, s -> s.length());
К сожалению, он не отсортирован по результату.