Я относительно новичок в Java и часто нахожу, что мне нужно отсортировать Map<Key, Value>
значения.
Поскольку значения не являются уникальными, я обнаружил, что преобразую их keySet
в array
массив и сортирую этот массив с помощью сортировки по массиву с помощью специального компаратора, который сортирует по значению, связанному с ключом.
Есть ли более простой способ?
List<Map.Entry<...>> list =new LinkedList(map.entrySet())
иCollections.sort ....
так.Ответы:
Вот универсальная версия:
источник
forEachOrdered
вместоforEach
документовforEach
состояния: «Поведение этой операции явно недетерминировано»?Важная заметка:
Этот код может сломаться несколькими способами. Если вы намереваетесь использовать предоставленный код, обязательно прочитайте комментарии, чтобы знать о последствиях. Например, значения больше не могут быть получены по их ключу. (
get
всегда возвращаетсяnull
.)Кажется, намного проще, чем все вышеперечисленное. Используйте TreeMap следующим образом:
Вывод:
источник
return ((Comparable)base.get(a).compareTo(((Comparable)base.get(b)))
?map.put("A","1d");map.put("B","1d");map.put("C",67d);map.put("D",99.5d);
Java 8 предлагает новый ответ: преобразовать записи в поток и использовать комбинаторы компаратора из Map.Entry:
Это позволит вам использовать записи, отсортированные в порядке возрастания значений. Если вам нужно нисходящее значение, просто поменяйте местами компаратор:
Если значения не сопоставимы, вы можете передать явный компаратор:
Затем вы можете перейти к использованию других потоковых операций для использования данных. Например, если вы хотите топ-10 на новой карте:
Или распечатайте на
System.out
:источник
parallelStream()
в этом случае?Три однострочных ответа ...
Я бы использовал
Google CollectionsGuava для этого - если ваши значения,Comparable
то вы можете использоватьКоторый создаст функцию (объект) для карты [которая принимает любую из клавиш в качестве входных данных, возвращая соответствующее значение], а затем применяет естественное (сопоставимое) упорядочение к ним [значениям].
Если они несопоставимы, то вам нужно сделать что-то вроде
Они могут быть применены к TreeMap (как
Ordering
расширяетComparator
) или LinkedHashMap после некоторой сортировкиNB . Если вы собираетесь использовать TreeMap, помните, что если сравнение == 0, то элемент уже находится в списке (что произойдет, если у вас есть несколько значений, которые сравнивают одно и то же). Чтобы облегчить это, вы можете добавить свой ключ к компаратору следующим образом (при условии, что ваши ключи и значения
Comparable
):= Применить естественное упорядочение к значению, отображаемому ключом, и составить его с естественным упорядочением ключа
Обратите внимание, что это все равно не будет работать, если ваши ключи сравниваются с 0, но этого должно быть достаточно для большинства
comparable
элементов (какhashCode
,equals
иcompareTo
часто синхронизируются ...)Смотрите Ordering.onResultOf () и Functions.forMap () .
Реализация
Итак, теперь, когда у нас есть компаратор, который делает то, что мы хотим, нам нужно получить от него результат.
Теперь это, скорее всего, будет работать, но:
TreeMap
; нет смысла пытаться сравнивать вставленный ключ, когда он не имеет значения, до окончания операции, т. е. он очень быстро сломаетсяПункт 1 для меня немного нарушает условия сделки; Коллекции Google невероятно ленивы (и это хорошо: вы можете выполнять практически все операции за один раз; настоящая работа выполняется, когда вы начинаете использовать результат), а для этого нужно скопировать всю карту!
«Полный» ответ / Live отсортированная карта по значениям
Не волнуйтесь, хотя; если вы были достаточно одержимы сортировкой «живой» карты таким образом, вы могли бы решить не одну, а обе (!) из вышеуказанных проблем с помощью чего-то сумасшедшего, например:
Примечание. Это значительно изменилось в июне 2012 года - предыдущий код никогда не работал: требуется внутренний HashMap для поиска значений без создания бесконечного цикла между
TreeMap.get()
->compare()
иcompare()
->get()
Когда мы помещаем, мы гарантируем, что хэш-карта имеет значение для компаратора, а затем помещаем его в TreeSet для сортировки. Но перед этим мы проверяем хеш-карту, чтобы увидеть, что ключ на самом деле не является дубликатом. Кроме того, созданный нами компаратор также будет включать ключ, чтобы дублированные значения не удаляли неповторяющиеся ключи (из-за сравнения ==). Эти 2 пункта жизненно важны для обеспечения соблюдения контракта карты; если вы думаете, что не хотите этого, то вы почти полностью изменили карту
Map<V,K>
.Конструктор должен быть вызван как
источник
Ordering
это просто богатыйComparator
. Я пытался комментировать каждый пример (курсив под каждым). «естественный» указывает, что объектыComparable
; это как ComparableComparator Apache Common.onResultOf
применяет функцию к сравниваемому элементу. Так что если бы у вас была функция, которая добавляла 1 к целому числу, тоnatural().onResultOf(add1Function).compare(1,2)
в конечном итоге это делалось бы2.compareTo(3)
ImmutableSetMultiMap
илиImmutableListMultiMap
содержать коллекцию дубликатов переменных.С http://www.programmersheaven.com/download/49349/download.aspx
источник
В Java 8 вы можете использовать API потоков, чтобы сделать это значительно менее многословно:
источник
Collections.reverseOrder(comparing(Entry::getValue))
Entry.comparingByValue(Comparator.reverseOrder())
Сортировка ключей требует, чтобы Comparator просматривал каждое значение для каждого сравнения. Более масштабируемое решение будет использовать entrySet напрямую, так как тогда значение будет сразу доступно для каждого сравнения (хотя я не подкреплял это цифрами).
Вот общая версия такой вещи:
Есть способы уменьшить вращение памяти для вышеуказанного решения. Первый созданный ArrayList может, например, использоваться повторно в качестве возвращаемого значения; это потребовало бы подавления некоторых общих предупреждений, но это могло бы стоить того, чтобы повторно использовать библиотечный код. Кроме того, Comparator не нужно перераспределять при каждом вызове.
Вот более эффективная, хотя и менее привлекательная версия:
Наконец, если вам нужен постоянный доступ к отсортированной информации (а не просто сортировать ее время от времени), вы можете использовать дополнительную мультикарту. Дайте мне знать, если вам нужно больше деталей ...
источник
Библиотека commons-collection содержит решение под названием TreeBidiMap . Или вы можете взглянуть на API Google Collections. У него есть TreeMultimap, который вы можете использовать.
И если вы не хотите использовать эти рамки ... они поставляются с исходным кодом.
источник
Я посмотрел на приведенные ответы, но многие из них сложнее, чем нужно, или удаляют элементы карты, когда несколько ключей имеют одинаковое значение.
Вот решение, которое, я думаю, подходит лучше:
Обратите внимание, что карта отсортирована от самого высокого значения до самого низкого.
источник
Для этого с новыми функциями в Java 8:
Записи упорядочены по их значениям с использованием данного компаратора. В качестве альтернативы, если ваши значения взаимно сопоставимы, явный компаратор не требуется:
Возвращенный список является снимком данной карты в момент вызова этого метода, поэтому ни один из них не отразит последующие изменения другого. Для живого итеративного просмотра карты:
Возвращаемая итерация создает новый снимок данной карты при каждой итерации, поэтому, за исключением одновременной модификации, она всегда будет отражать текущее состояние карты.
источник
Создайте собственный компаратор и используйте его при создании нового объекта TreeMap.
Используйте приведенный ниже код в своей основной функции
Вывод:
источник
Хотя я согласен с тем, что постоянная необходимость сортировать карту, вероятно, является запахом, я думаю, что следующий код - это самый простой способ сделать это без использования другой структуры данных.
}
И вот смущающе неполный юнит-тест:
}
Результатом является отсортированный список объектов Map.Entry, из которого можно получить ключи и значения.
источник
Используйте общий компаратор, такой как:
источник
Ответ, за который проголосовали большинство, не работает, если у вас есть 2 равных элемента. TreeMap оставляет равные значения.
пример: несортированная карта
Результаты
Так что пропускаем E !!
Для меня это работало нормально, чтобы настроить компаратор, если он не возвращает 0, а -1.
в примере:
теперь возвращается:
несортированная карта:
Результаты:
в ответ на Aliens (2011, нов. 22): я использую это решение для карты целочисленных идентификаторов и имен, но идея та же, поэтому приведенный выше код может быть неправильным (я напишу его в тесте и дать вам правильный код), это код для сортировки карт, основанный на решении выше:
и это тестовый класс (я только что проверил, и это работает для Integer, String Map:
Вот код для компаратора карты:
и это тест для этого:
Конечно, вы можете сделать это намного более общим, но мне просто нужно было это для 1 случая (Карта)
источник
Вместо использования,
Collections.sort
как некоторые, я бы предложил использоватьArrays.sort
. На самом деле, что-Collections.sort
то вроде этого:Он просто вызывает
toArray
в списке, а затем используетArrays.sort
. Таким образом, все записи карты будут скопированы три раза: один раз из карты во временный список (будь то LinkedList или ArrayList), затем во временный массив и, наконец, в новую карту.Мое решение пропускает этот один шаг, поскольку оно не создает ненужный LinkedList. Вот код, универсальный и оптимальный по производительности:
источник
Это вариант ответа Энтони, который не работает, если есть повторяющиеся значения:
Обратите внимание, что это довольно важно, как обрабатывать нули.
Одним из важных преимуществ этого подхода является то, что он на самом деле возвращает карту, в отличие от некоторых других решений, предлагаемых здесь.
источник
Лучший подход
Вывод
источник
Серьезная проблема. Если вы используете первый ответ (Google берет вас здесь), измените компаратор, чтобы добавить равное предложение, иначе вы не сможете получить значения из sorted_map по ключам:
источник
На этот вопрос уже есть много ответов, но ни один из них не дал мне того, что я искал, реализацию карты, которая возвращает ключи и записи, отсортированные по ассоциированному значению, и поддерживает это свойство, поскольку ключи и значения изменяются в карте. Два других вопроса задают это специально.
Я подготовил общий дружественный пример, который решает этот вариант использования. Эта реализация не учитывает все контракты интерфейса Map, такие как отражение изменений и удалений значений в наборах, возвращаемых из keySet () и entrySet () в исходном объекте. Я чувствовал, что такое решение будет слишком большим, чтобы включить его в ответ на переполнение стека. Если мне удастся создать более полную реализацию, возможно, я опубликую ее на Github, а затем на ссылку в обновленной версии этого ответа.
источник
Поздний вход.
С появлением Java-8 мы можем использовать потоки для манипулирования данными очень простым / лаконичным способом. Вы можете использовать потоки, чтобы отсортировать записи карты по значению и создать LinkedHashMap, который сохраняет итерацию порядка вставки .
Например:
Для обратного заказа замените:
с
источник
Entry.comparingByValue()
(как в ответе ассилий выше stackoverflow.com/a/22132422/1480587 ) илиcomparing(Entry<Key,Value>::getValue).thenComparing(Entry::getKey)
что вы использовали? Я так понимаю, вы также сравниваете ключи, если значения идентичны, верно? Я заметил, что сортировка поддерживает порядок элементов с одинаковым значением - так нужна ли сортировка по ключам, если ключи уже были отсортированы раньше?Данная карта
Сортировать карту по значению в порядке возрастания
Сортировать карту по значению в порядке убывания
Вывод:
{программное обеспечение = 50, технология = 70, США = 100, работа = 200, возможность = 200}
{работа = 200, возможность = 200, США = 100, технология = 70, программное обеспечение = 50}
источник
В зависимости от контекста, использование
java.util.LinkedHashMap<T>
которого запоминает порядок, в котором элементы размещаются на карте. В противном случае, если вам нужно отсортировать значения на основе их естественного упорядочения, я бы порекомендовал вести отдельный список, который можно отсортировать черезCollections.sort()
.источник
Поскольку TreeMap <> не работает для значений, которые могут быть равны, я использовал это:
Возможно, вы захотите поместить список в LinkedHashMap , но если вы собираетесь сразу же повторить его, это лишнее ...
источник
Это слишком сложно. Карты не должны были выполнять такую работу, как сортировка их по значению. Самый простой способ - создать свой собственный класс, чтобы он соответствовал вашим требованиям.
В примере ниже вы должны добавить TreeMap компаратор в месте, где *. Но с помощью API Java он дает компаратору только ключи, а не значения. Все приведенные здесь примеры основаны на 2 картах. Один хэш и одно новое дерево. Что странно.
Пример:
Так что измените карту в набор следующим образом:
Вы создадите класс
Results
,и класс Comparator:
Таким образом, вы можете легко добавить больше зависимостей.
И в качестве последнего пункта я добавлю простой итератор:
источник
Основанный на коде @devinmoore, методы сортировки карт, использующие обобщенные типы и поддерживающие как возрастание, так и убывание.
источник
Вот решение OO (то есть, не использует
static
методы):Настоящим пожертвовано в общественное достояние.
источник
Afaik самый чистый способ - использовать коллекции для сортировки карты по значению:
источник
Несколько простых изменений, чтобы иметь отсортированную карту с парами, которые имеют повторяющиеся значения. В методе сравнения (класс ValueComparator), когда значения равны, не возвращают 0, а возвращают результат сравнения двух ключей. Ключи различны на карте, поэтому вам удастся сохранить дубликаты значений (которые, кстати, отсортированы по ключам). Таким образом, приведенный выше пример можно изменить следующим образом:
источник
Конечно, решение Стивена действительно великолепно, но для тех, кто не может использовать гуаву:
Вот мое решение для сортировки по значению карты. Это решение обрабатывает случай, когда есть два одинаковых значения и т.д ...
Exec: http://www.ideone.com/dq3Lu
Выход:
Надеюсь, это поможет некоторым людям
источник
Если у вас есть дубликаты ключей и только небольшой набор данных (<1000) и ваш код не критичен по производительности, вы можете просто сделать следующее:
inputUnsortedMap - это ввод кода.
Переменная sortedOutputMap будет содержать данные в порядке убывания при повторном выполнении. Чтобы изменить порядок, просто измените> на <в операторе if.
Не самая быстрая сортировка, но делает работу без каких-либо дополнительных зависимостей.
источник