Клас Java, який реалізує Map і підтримує порядок вставки?


463

Я шукаю клас в java, який має асоціацію ключових значень, але без використання хешів. Ось що я зараз роблю:

  1. Додайте значення до Hashtable.
  2. Отримайте ітератор для Hashtable.entrySet().
  3. Ітерація через усі значення та:
    1. Отримайте Map.Entryітератор.
    2. Створіть об’єкт типу Module(спеціальний клас) на основі значення.
    3. Додайте клас до JPanel.
  4. Покажіть панель.

Проблема в цьому полягає в тому, що я не маю контролю над порядком, щоб я повертав значення, тому я не можу відображати значення в заданому порядку (без жорсткого кодування порядку).

Я б використовував ArrayListабо Vectorдля цього, але пізніше в коді мені потрібно захопити Moduleоб'єкт для даного ключа, що я не можу зробити з ArrayListабо Vector.

Хтось знає про вільний / відкритий код Java-класу, який це зробить, або спосіб отримати значення на Hashtableоснові, коли вони були додані?

Дякую!


1
Вам не потрібно використовувати enterset / map.entry. ви можете перебирати ключі та значення, використовуючи hashtable.keys як перерахунок або використовуючи hashtable.keyset.iterator.
Джон Гарднер

5
Я взяв на себе сміливість змінити назву, оскільки використання хесів насправді не проблема, але дотримання порядку вставки.
Йоахім Зауер

Відповіді:


734

Я пропоную LinkedHashMapабо TreeMap. A LinkedHashMapзберігає ключі в тому порядку, в який вони були вставлені, а a TreeMapзберігається впорядкованим шляхом Comparatorабо шляхом природного Comparableвпорядкування елементів.

Оскільки для цього не потрібно впорядковувати елементи сортування, LinkedHashMapу більшості випадків повинно бути швидше; TreeMapмає O(log n)продуктивність containsKey, get, put, і remove, в відповідно до Javadocs, в той час як LinkedHashMapце O(1)для кожного.

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


2
Це не спрацює для мене, оскільки, згідно з javadocs, це дає лише впорядковані значення (через виклик значень ()). Чи є спосіб замовити примірники Map.Entry?
Кори Кендалл

1
@CoryKendall: Чи TreeMap не працює? Він повинен бути відсортований за ключами, а не за значеннями.
Майкл Майерс

1
Моя помилка, я вважав, що набори були несортованими.
Кори Кендалл

61
Зверніть увагу: сортування TreeMap ґрунтується на природному порядку клавіш: "Карта сортується відповідно до природного упорядкування її клавіш". LinkedHashMap відсортований у порядку вставки bij. Велика різниця!
Jop van Raaij

3
@AlexR: Це справедливо лише в тому випадку, якщо LinkedHashMap був створений за допомогою спеціального конструктора, який передбачений для цієї мети. За замовчуванням ітерація знаходиться в порядку вставки.
Майкл Майерс

22

LinkedHashMap поверне елементи в тому порядку, який вони були вставлені в карту, коли ви переходите до keySet (), entrySet () або значень () карти.

Map<String, String> map = new LinkedHashMap<String, String>();

map.put("id", "1");
map.put("name", "rohan");
map.put("age", "26");

for (Map.Entry<String, String> entry : map.entrySet()) {
    System.out.println(entry.getKey() + " = " + entry.getValue());
}

Це надрукує елементи в тому порядку, як вони були розміщені на карті:

id = 1
name = rohan 
age = 26 

16

Якщо незмінна карта відповідає вашим потребам, то існує бібліотека google під назвою guava (див. Також питання guava )

Guava забезпечує ImmutableMap із надійним замовленням на ітерацію, визначене користувачем. Ця ImmutableMap має O (1) продуктивність для containsKey, get. Очевидно, що поставлені та видалені не підтримуються.

Об'єкти ImmutableMap створюються за допомогою елегантних статичних методів зручності () і copyOf () або об'єкта Builder .


6

Ви можете підтримувати Map(для швидкого пошуку) та List(для замовлення), але LinkedHashMapможе бути найпростішим. Ви також можете спробувати, SortedMapнаприклад TreeMap, який у вас є будь-який порядок, який ви вказали.


1

Я не знаю, чи це відкритий код, але після невеликого гуглінгу я знайшов цю реалізацію Map за допомогою ArrayList . Здається, це Java до 1,5, тому ви, можливо, захочете генерувати її, що має бути простим. Зауважте, що ця реалізація має доступ до O (N), але це не повинно бути проблемою, якщо ви не додасте сотні віджетів у свій JPanel, чого ви все одно не повинні.



1

Щоразу, коли мені потрібно підтримувати природний порядок речей, які відомі достроково, я використовую EnumMap

ключі будуть перерахунками, і ви можете вставляти їх у будь-якому бажаному порядку, але коли ви повторюєте, він повторюється в порядку перерахування (природний порядок).

Також при використанні EnumMap не повинно бути зіткнень, які можуть бути більш ефективними.

Я дійсно вважаю, що використання enumMap робить чистим читабельний код. Ось приклад


1

Ви можете використовувати LinkedHashMap для основного порядку вставки в Map

Важливі моменти щодо класу Java LinkedHashMap:

  1. Він містить лише унікальні елементи.
  2. LinkedHashMap містить значення на основі ключа 3. Він може мати один нульовий ключ і кілька нульових значень. 4. Це те саме, що HashMap замість цього підтримує порядок вставки

    public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> 

Але якщо ви хочете сортувати значення на карті за допомогою визначеного користувачем об’єкта або будь-якого примітивного ключа типу даних, тоді вам слід використовувати TreeMap. Для отримання додаткової інформації перейдіть за цим посиланням


0

Або Ви можете використовувати, LinkedHashMap<K, V>або можете реалізувати власний CustomMap, який підтримує порядок вставки.

Ви можете використовувати наступне CustomHashMapз такими функціями:

  • Порядок вставки підтримується за допомогою внутрішнього використання LinkedHashMap.
  • Ключі с null або порожніми рядками заборонені.
  • Після створення ключа зі значенням ми не переосмислюємо його значення.

HashMapпроти LinkedHashMapvsCustomHashMap

interface CustomMap<K, V> extends Map<K, V> {
    public boolean insertionRule(K key, V value);
}

@SuppressWarnings({ "rawtypes", "unchecked" })
public class CustomHashMap<K, V> implements CustomMap<K, V> {
    private Map<K, V> entryMap;
    // SET: Adds the specified element to this set if it is not already present.
    private Set<K> entrySet;

    public CustomHashMap() {
        super();
        entryMap = new LinkedHashMap<K, V>();
        entrySet = new HashSet();
    }

    @Override
    public boolean insertionRule(K key, V value) {
        // KEY as null and EMPTY String is not allowed.
        if (key == null || (key instanceof String && ((String) key).trim().equals("") ) ) {
            return false;
        }

        // If key already available then, we are not overriding its value.
        if (entrySet.contains(key)) { // Then override its value, but we are not allowing
            return false;
        } else { // Add the entry
            entrySet.add(key);
            entryMap.put(key, value);
            return true;
        }
    }
    public V put(K key, V value) {
        V oldValue = entryMap.get(key);
        insertionRule(key, value);
        return oldValue;
    }
    public void putAll(Map<? extends K, ? extends V> t) {
        for (Iterator i = t.keySet().iterator(); i.hasNext();) {
            K key = (K) i.next();
            insertionRule(key, t.get(key));
        }
    }

    public void clear() {
        entryMap.clear();
        entrySet.clear();
    }
    public boolean containsKey(Object key) {
        return entryMap.containsKey(key);
    }
    public boolean containsValue(Object value) {
        return entryMap.containsValue(value);
    }
    public Set entrySet() {
        return entryMap.entrySet();
    }
    public boolean equals(Object o) {
        return entryMap.equals(o);
    }
    public V get(Object key) {
        return entryMap.get(key);
    }
    public int hashCode() {
        return entryMap.hashCode();
    }
    public boolean isEmpty() {
        return entryMap.isEmpty();
    }
    public Set keySet() {
        return entrySet;
    }
    public V remove(Object key) {
        entrySet.remove(key);
        return entryMap.remove(key);
    }
    public int size() {
        return entryMap.size();
    }
    public Collection values() {
        return entryMap.values();
    }
}

Використання CustomHashMap:

public static void main(String[] args) {
    System.out.println("== LinkedHashMap ==");
    Map<Object, String> map2 = new LinkedHashMap<Object, String>();
    addData(map2);

    System.out.println("== CustomHashMap ==");
    Map<Object, String> map = new CustomHashMap<Object, String>();
    addData(map);
}
public static void addData(Map<Object, String> map) {
    map.put(null, "1");
    map.put("name", "Yash");
    map.put("1", "1 - Str");
    map.put("1", "2 - Str"); // Overriding value
    map.put("", "1"); // Empty String
    map.put(" ", "1"); // Empty String
    map.put(1, "Int");
    map.put(null, "2"); // Null

    for (Map.Entry<Object, String> entry : map.entrySet()) {
        System.out.println(entry.getKey() + " = " + entry.getValue());
    }
}

O / P:

== LinkedHashMap == | == CustomHashMap ==
null = 2            | name = Yash
name = Yash         | 1 = 1 - Str
1 = 2 - Str         | 1 = Int
 = 1                |
  = 1               |
1 = Int             |

Якщо ви знаєте, що ключі виправлені, ви можете використовувати EnumMap. Отримайте значення форми Властивості / XML-файли

EX:

enum ORACLE {
    IP, URL, USER_NAME, PASSWORD, DB_Name;
}

EnumMap<ORACLE, String> props = new EnumMap<ORACLE, String>(ORACLE.class);
props.put(ORACLE.IP, "127.0.0.1");
props.put(ORACLE.URL, "...");
props.put(ORACLE.USER_NAME, "Scott");
props.put(ORACLE.PASSWORD, "Tiget");
props.put(ORACLE.DB_Name, "MyDB");
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.