Как сначала отсортировать карту с помощью ключа, а также отсортировать значения.
Map<String, List<String>> myMap = new HashMap<>();
myMap.put("Apple", Arrays.asList("iphone", "imac"));
myMap.put("Samsung", Arrays.asList("galaxys", "galaxyz"));
myMap.put("LG", Arrays.asList("ultra", "tab"));
//sort logic
Sort with the key first {Apple, LG, Samsung} and then sort the values based on the key.
Результат:
imac, iphone, tab, ultra, galaxys, galaxyz
Правильный. Сначала отсортируйте ключ и на основе отсортированного ключа отсортируйте список значений (объединенный).
Если вы хотите, чтобы карта была отсортирована по ключу, почему бы не использовать TreeMap?
Во-первых, поток по записям карты. Следовательно, отсортируйте их с помощью компаратора Map.Entry.comparingByKey(). Теперь, когда у вас есть список записей, отсортированный по ключам, сопоставьте значения (списки), отсортировав их с помощью Collections.sort(). Следовательно, плоская карта и сбор в список.
У вас есть серьезная проблема: HashMap неупорядочен, поэтому его сортировка не имеет смысла. Есть LinkedHashMap для порядка вставки или TreeMap extends SortedMap для... отсортированной карты.




public static Map<String, List<String>> sortMapList(Map<String, List<String>> myMap) {
Map<String, List<String>> sortedMap = new TreeMap<>();
myMap.entrySet().stream()
.forEach(x -> sortedMap.put(x.getKey(), x.getValue().stream()
.sorted().collect(Collectors.toList()))
);
return sortedMap;
}
Это возвращает карту, а не плоский список. Кроме того, тот факт, что вы инициализируете sortedMap как HashMap, не дает вам никаких гарантий, что ключи все равно будут отсортированы при выполнении цикла. также есть способ создать список напрямую через сбор без необходимости использования промежуточного объекта.
Map.Entry.comparingByKey() сравнивает Map.Entry в естественном порядке по ключу.
Вы перебираете карту по порядку, но помещаете ее обратно в неупорядоченный HashMap, в результате чего сортируются только List. Сортировка по ключу фактически игнорируется.
Вместо myMap.entrySet().stream().forEach(x -> …), вызывая x.getKey() и x.getValue() в функции, вы можете в первую очередь использовать myMap.forEach((key, value) -> …).
Проще решить проблемы потока, составив план. Примером этой проблемы может быть:
Stream<Map.Entry<String, List<String>>>)Stream<List<String>>)Stream<String>)List<String>)Сначала вам придется преобразовать карту в entrySet, чтобы обеспечить потоковую передачу по записям Map.Entry. Затем мы можем отсортировать списки с помощью ключа карты с помощью .sorted(Map.Entry.comparingByKey()) и .map(Map.Entry::getValue).
Когда списки отсортированы, элементы внутри не сортируются. Поэтому нам нужно сгладить их (перейти от Stream<List<String>> к Stream<String>, содержащему элементы списков) в отсортированном порядке: .flatMap(list -> list.stream().sorted())
Результат: код:
List<String> result = myMap.entrySet().stream() // Step 1
.sorted(Map.Entry.comparingByKey()) // Step 2
.map(Map.Entry::getValue) // Step 3
.flatMap(list -> list.stream().sorted()) // Step 4+5
.collect(Collectors.toList()); // Step 6
Вы также можете пропустить сопоставление с Map.Entry::getValue, выполнив .flatMap(entry -> entry.getValue().stream().sorted()) напрямую, но тогда будет немного менее понятно, что происходит.
Или 4+5 можно использовать ссылки на методы .map(List::stream).flatMap(Stream::sorted)
Или пойдите в другом направлении и объедините шаги с 3 по 5 в один, .flatMap(e -> e.getValue().stream().sorted())
Обратите внимание, что HashMap неупорядочен: вообще не существует понятия сортировки HashMap. При изменении карты порядок клавиш может измениться непредсказуемо. В этом случае мы можем использовать TreeMap (который расширяет SortedMap), чтобы избежать проблемы с порядком HashMap:
Map<String, List<String>> myMap = new TreeMap<>();
myMap.put("Apple", Arrays.asList("iphone", "imac"));
myMap.put("Samsung", Arrays.asList("galaxys", "galaxyz"));
myMap.put("LG", Arrays.asList("ultra", "tab"));
Это позволяет вам получать отсортированный вывод напрямую с потоками (обратите внимание на вызов #sort внутри #flatMap):
List<String> sorted = myMap.values().stream().flatMap(l -> l.sort().stream()).toList();
// ["imac", "iphone", "tab", "ultra", "galaxys", "galaxyz"]
Лучшим подходом может быть сохранение внутренних списков (читай: наборов), отсортированных для начала:
Map<String, Set<String>> myMap = new TreeMap<>();
myMap.put("Apple", new TreeSet<>(Arrays.asList("iphone", "imac")));
myMap.put("Samsung", new TreeSet<>(Arrays.asList("galaxys", "galaxyz")));
myMap.put("LG", new TreeSet<>(Arrays.asList("ultra", "tab")));
Теперь ваши значения всегда будут отсортированы, даже при обновлении:
myMap.get("Apple").add("ipad");
List<String> sorted = myMap.values().stream().flatMap(Set::stream).toList();
// ["imac", "ipad", "iphone", "tab", "ultra", "galaxys", "galaxyz"]
Обратите внимание, что это решение предпочтительнее, если вы можете контролировать тип карты, но не в том случае, если вам просто дали Map<X,Y> и вам нужно отсортировать ее таким образом. Хотя в вопросе не упоминается, так это или нет.
Если это так, они могут взглянуть на ваш ответ :). Обратите внимание, что в Java 16 введен Stream#toList для удобства набора текста.
@ ipodtouch0218 прав, Карта предоставлена, и я не могу ее контролировать. Таким образом, данная карта, к сожалению, является HashMap.
Вот своего рода гибридное решение.
ArrayList<String>Entry на месте. List<String> result = new ArrayList<>();
myMap.entrySet().forEach(e -> e.getValue().sort(null));
myMap.entrySet().stream()
.sorted(Entry.comparingByKey())
.map(Entry::getValue)
.forEach(lst -> result.addAll(lst));
принты
[imac, iphone, tab, ultra, galaxys, galaxyz]
Вместо myMap.entrySet().forEach(e -> e.getValue().sort(null)); вы можете использовать myMap.values().forEach(v -> v.sort(null));, myMap.values().forEach(Collections::sort); или myMap.forEach((k, v) -> v.sort(null));. Но имейте в виду, что это предполагает, что списки в исходной карте изменяемы.
@Holger Просто не рассматривал возможность прямого использования значений. Но я учитывал изменчивость списков. Основываясь на данных и конструкции, предоставленных ОП, я решил, что все в порядке. Спасибо за предложения!
Да, в примере кода вопроса указана изменчивость. Но это может быть слишком упрощенный пример, поэтому стоит явно упомянуть об ограничениях.
поэтому в основном вы хотите, чтобы каждый список сортировался независимо (сначала), а затем сортировался по ключу и все списки (значения) были объединены.