Замовлена ​​карта Java


322

У Java чи існує об'єкт, який діє як Карта для зберігання та доступу до пар ключів / значень, але може повернути впорядкований список ключів та упорядкований список значень, таким чином, щоб списки ключів та значень були в одному порядку?

Тож як пояснення за кодом я шукаю те, що поводиться як моя вигадана OrdersMap:

OrderedMap<Integer, String> om = new OrderedMap<>();
om.put(0, "Zero");
om.put(7, "Seven");

String o = om.get(7); // o is "Seven"
List<Integer> keys = om.getKeys();
List<String> values = om.getValues();

for(int i = 0; i < keys.size(); i++)
{
    Integer key = keys.get(i);
    String value = values.get(i);
    Assert(om.get(key) == value);
}

4
Якщо все, що ви хочете зробити, це повторення обох одночасно, то Map.entrySet () дозволить вам робити це на будь-якій карті. LinkedHashMap має чітко визначений порядок, але для будь-якої карти набір відображає пари ключ / значення.
Піт Кіркхем,

5
Цей код не є хорошим прикладом, оскільки будь-яка реалізація карти буде поводитись як зразок коду. сортував, замовляв чи ні.
Пітер Лоурі

2
У реалізації JDK Sun, набори, повернені наборами getKeys та getValues ​​(), підкріплюються на карті entrySet (), тому буде мати такий самий порядок ітерації, що і тест вашого зразка.
Піт Кіркхем

4
Ну це цікаво, я цього ніколи не помічав. Все-таки називайте мене божевільним, але я вважаю за краще не робити припущень щодо реалізації, які не підтверджені явно інтерфейсом. Мене занадто багато разів спалювали, роблячи це в минулому.
Whatsit

2
Цю назву слід назвати сортованою на Java картою, оскільки впорядкована карта дещо інша - див LinkedHashMap.
Ondra Žižka

Відповіді:


397

Інтерфейс SortedMap (з реалізацією TreeMap ) повинен бути вашим другом.

В інтерфейсі є методи:

  • keySet() який повертає набір ключів у порядку зростання
  • values() який повертає колекцію всіх значень у порядку зростання відповідних клавіш

Тож цей інтерфейс відповідає саме вашим вимогам. Однак ключі повинні мати змістовний порядок. В іншому випадку ви можете використовувати LinkedHashMap, де порядок визначається порядком вставки.


2
приклад: SortedMap <String, Object> map = новий TreeMap <> ();
Бен

7
Для використання TreeMap потрібно було, щоб клас класів мав реалізувати Порівнюваний інтерфейс. Якщо ні, то буде викинуто якесь RuntimeException. TreeMap це також сортована карта, але я думаю, що автор хоче використовувати тільки замовлену (не відсортовану) карту. LinkedHashMap - це гарний вибір отримати лише замовлену карту (як ви сказали, "визначається порядком вставки").
К. Гол

1
цю відповідь можна покращити, показавши, як перейти через keySet ()

4
Від java 8 doc . LinkedHashMapчий порядок ітерації - це порядок, коли в останній раз були доступні його записи
TRiNE

1
@TRiNE Я не стежу за вашим коментарем, але, можливо, я пропустив якийсь контекст. За замовчуванням LinkedHashMapітераційний порядок - це порядок вставки, але ви можете використовувати інший конструктор, щоб вказати замовлення доступу. docs.oracle.com/javase/8/docs/api/java/util/…
пограбувати

212

Чи є об’єкт, який діє як Карта для зберігання та доступу до пар ключів / значень, але може повернути упорядкований список ключів та упорядкований список значень, таким чином, що списки ключів та значень у тому ж порядку?

Ви шукаєте java.util.LinkedHashMap . Ви отримаєте список пар Map.Entry <K, V> , які завжди повторюються в одному порядку. Цей порядок такий самий, як і порядок, у який ви вводите елементи. Як варіант, використовуйте java.util.SortedMap , де ключі повинні мати природне впорядкування або вказати його Comparator.


14
І просто зберегти читача подвійну перевірку цього, оскільки це важко перевірити тестуванням, keySet()метод ефективно повертає LinkedHashSet, який відображає порядок ваших put()дзвінків. Зауважте, що повторні дзвінки до put()однієї клавіші не змінять порядок, якщо ви не remove()введете попередньо клавішу.
Глен Лоуренс

Від java 8 doc . LinkedHashMapчий порядок ітерації - це порядок, коли в останній раз були доступні його записи
TRiNE

24

LinkedHashMap підтримує порядок клавіш.

java.util.LinkedHashMap, здається, працює так само, як і звичайний HashMap в іншому випадку.


1
Це не дає відповіді на запитання. Щоб критикувати або вимагати роз'яснення у автора, залиште коментар під їх публікацією - ви завжди можете коментувати свої власні публікації, і як тільки у вас буде достатня репутація, ви зможете коментувати будь-яку публікацію .
ianaya89

2
@ ianaya89 Я думаю, що це справжня відповідь, але це дуже схоже на відповідь Джона Фемінелла !
T30

1
Якщо ви хочете отримати впорядковану карту, де записи зберігаються в тому порядку, коли ви розміщуєте їх на карті, ніж LinkedHashMap є правильною відповіддю. Якщо ви хочете сортувати записи на своїй карті незалежно від порядку їх введення, то SortedMap - це правильна відповідь.
Ральф

@TRiNE Java 8 doc, який ви зв'язали, говорить про можливі два режими впорядкування: порядок вставки та замовлення доступу. Ви думаєте про останнє, на яке викликається використання спеціального конструктора public LinkedHashMap (int InitialCapacity, float loadFactor, boolean accessOrder). Конструктор за замовчуванням створює впорядкований вставку LinkedHashMap.
Артур Лисик

1
@ ArturŁysik так. Це була помилка, зроблена мною кілька днів тому. Я виправлю це. Я видаляю коментар. оскільки я більше не можу це редагувати
TRiNE

7

Я думаю, що найближча колекція, яку ти отримаєш від рамок, - це SortedMap


3
Я би відмовився голосувати за цю відповідь, якби я вважав, що варто втратити бали за неї. Як вказується вище відповідь, у вашій відповіді бракує належної інформації про LinkedHashMap, і трохи пояснень SortedMap було б непогано.
CorayThan

@CorayThan, у такому випадку ви схвалюєте найкращі відповіді, а не відхиляєте інших, які можуть бути правильними, але не найкращими ...
bruno conde

1
Це я і зробив. Тільки кажучи, я можу зрозуміти, чому хтось відмовився би проголосувати за це.
CorayThan

5

Ви можете використовувати інтерфейс NavigableMap, до якого можна отримати доступ та пройти в порядку числення у порядку зростання чи зменшенні. Цей інтерфейс призначений для заміщення інтерфейсу SortedMap. Навігаційна карта зазвичай сортується відповідно до природного упорядкування клавіш або за допомогою компаратора, який надається під час створення карти.

Є три найбільш корисних реалізацій нього: TreeMap , ImmutableSortedMap і ConcurrentSkipListMap .

Приклад TreeMap:

TreeMap<String, Integer> users = new TreeMap<String, Integer>();
users.put("Bob", 1);
users.put("Alice", 2);
users.put("John", 3);

for (String key: users.keySet()) {
  System.out.println(key + " (ID = "+ users.get(key) + ")");
}

Вихід:

Alice (ID = 2)
Bob (ID = 1)
John (ID = 3)



2

тл; д-р

Для збереження Map< Integer , String >в порядку, відсортованому за ключовими словами, використовуйте будь-який з двох класів, що реалізують SortedMap/ NavigableMapінтерфейси:

  • TreeMap
  • ConcurrentSkipListMap

Якщо ви маніпулюєте картою в одному потоці, використовуйте перший TreeMap,. Якщо маніпулюючи різними потоками, використовуйте другий, ConcurrentSkipListMap.

Детальніше дивіться у таблиці нижче та наступному обговоренні.

Деталі

Ось графічна таблиця, яку я склав, що показує особливості десяти Mapреалізацій в комплекті з Java 11.

NavigableMapІнтерфейс , що SortedMapмає бути в першу чергу. SortedMapЛогічно повинні бути видалені , але не може бути , як деякі карти реалізації третьої сторони може використовувати інтерфейс.

Як ви бачите в цій таблиці, лише два класи реалізують SortedMap/ NavigableMapінтерфейси:

Обидва ці ключі зберігають у відсортованому порядку або за їх природним порядком (використовуючи compareToметод Comparable( https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/ Comparable.html ) інтерфейс) або через Comparatorпередачу, яку ви проходите. Різниця між цими двома класами полягає в тому, що другий ConcurrentSkipListMap, є безпечним для потоків , високо сумісним .

Дивіться також стовпець Порядок ітерацій у таблиці нижче.

  • LinkedHashMapКлас повертає свої записи по порядку , в якому вони були спочатку вставлені .
  • EnumMapповертає записи в тому порядку, в якому визначається клас enum ключа . Наприклад, карта якого співробітника покриває, який день тижня ( Map< DayOfWeek , Person >) використовує DayOfWeekклас enum, вбудований у Java. Цей перелік визначається з понеділка першого та останнього неділі. Тож записи в ітераторі з’являться в тому порядку.

Інші шість реалізацій не обіцяють щодо порядку, в якому вони повідомляють про свої записи.

Таблиця реалізацій карт на Java 11, порівняння їх особливостей


0

Я використовував просту карту Hash, пов'язаний список та колекції для сортування карти за значеннями.

import java.util.*;
import java.util.Map.*;
public class Solution {

    public static void main(String[] args) {
        // create a simple hash map and insert some key-value pairs into it
        Map<String, Integer> map = new HashMap<String, Integer>();
        map.put("Python", 3);
        map.put("C", 0);
        map.put("JavaScript", 4);
        map.put("C++", 1);
        map.put("Golang", 5);
        map.put("Java", 2);
        // Create a linked list from the above map entries
        List<Entry<String, Integer>> list = new LinkedList<Entry<String, Integer>>(map.entrySet());
        // sort the linked list using Collections.sort()
        Collections.sort(list, new Comparator<Entry<String, Integer>>(){
        @Override
         public int compare(Entry<String, Integer> m1, Entry<String, Integer> m2) {
        return m1.getValue().compareTo(m2.getValue());
        }
      });
      for(Entry<String, Integer> value: list) {
         System.out.println(value);
     }
   }
}

Вихід:

C=0
C++=1
Java=2
Python=3
JavaScript=4
Golang=5
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.