Как добавить элемент по определенному индексу / позиции в LinkedHashMap? - PullRequest
41 голосов
/ 07 октября 2011

У меня есть заказанный LinkedHashMap, и я хочу добавить элемент по определенному индексу, скажем, на первом или последнем месте на карте.Как я могу добавить элемент в LinkedHashMap в определенной позиции?

Даже если бы я мог добавить элемент в первую или последнюю позицию в LinkedHashMap, это поможет!

Ответы [ 7 ]

20 голосов
/ 07 октября 2011

Вы не можете изменить порядок.Это insert-order (по умолчанию) или access-order с этим конструктором:

public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder)

  • Создает пустой экземпляр LinkedHashMap с указанным инициаломемкость, коэффициент загрузки и режим заказа.

  • Параметры: initialCapacity - начальная емкость loadFactor - коэффициент загрузки accessOrder - режим заказа - true для порядка доступа, false для порядка вставки

  • Броски: IllegalArgumentException - если начальная емкость отрицательна или коэффициент нагрузки неположителен

См .: LinkedHashMap

18 голосов
/ 30 ноября 2014

Вы можете сделать этот элемент, добавив к 1. или последнему месту:

Добавление к последнему месту ► Вам просто нужно удалить предыдущую запись с карты следующим образом:

map.remove(key);
map.put(key,value);

Добавление на первое место ► Это немного сложнее, вам нужно клонировать карту, очистить ее, присвоить ей значение 1. и поместить на нее новую карту, какthis:

Я использую карты со значениями ключей String и Group (мой пользовательский класс):

LinkedHashMap<String, Group> newmap=(LinkedHashMap<String, Group>) map.clone();
map.clear();
map.put(key, value);
map.putAll(newm);

Как видите, с помощью этих методов вы можете добавлять неограниченное количество вещей кначало и конец карты.

10 голосов
/ 11 июня 2017

Решение Apache Commons: ListOrderedMap

Поскольку JDK LinkedHashMap обеспечивает только извлечение порядка вставки, в случае, если вы хотите вставить индекс, мы можем использовать Apache Commons альтернативно 'ListOrderedMap. Он делает это так, как кажется - имея список для поддержания порядка вставки с соответствующим индексом и карту нормалей для вставки, как мы обычно это делаем. Вот что говорят документы :

public class ListOrderedMap<K,V>
extends AbstractMapDecorator<K,V>
implements OrderedMap<K,V>, Serializable

Украшает Map, чтобы обеспечить сохранение порядка добавления использование списка для поддержания порядка.

Порядок будет использоваться через итераторы и toArray методы на Просмотры. Заказ также возвращается MapIterator. orderedMapIterator() метод обращается к итератору, который может перебирать и вперед и назад по карте. К тому же, предоставляются неинтерфейсные методы для доступа к карте по индексу.

Если объект добавлен на карту во второй раз, он останется в исходная позиция в итерации.

Обратите внимание, что ListOrderedMap не синхронизируется и не является поточно-ориентированным. Если вы хотите использовать эту карту из нескольких потоков одновременно, вы необходимо использовать соответствующую синхронизацию. Самый простой подход - завернуть эта карта, используя Collections.synchronizedMap(Map). Этот класс может генерировать исключения при обращении к параллельным потокам без синхронизации.

Обратите внимание, что ListOrderedMap не работает с IdentityHashMap, CaseInsensitiveMap, или аналогичные карты, которые нарушают общие контракт Map. ListOrderedMap (или, точнее, базовый List) полагается на equals(). Это хорошо, пока декорированный Map также основан на equals() и hashCode(), которые IdentityHashMap и CaseInsensitiveMap не делают: бывший использует ==, а последний использует equals() для клавиши в нижнем регистре.

Вот его реализация для добавления в позицию:

        /**
428     * Puts a key-value mapping into the map at the specified index.
429     * <p>
430     * If the map already contains the key, then the original mapping
431     * is removed and the new mapping added at the specified index.
432     * The remove may change the effect of the index. The index is
433     * always calculated relative to the original state of the map.
434     * <p>
435     * Thus the steps are: (1) remove the existing key-value mapping,
436     * then (2) insert the new key-value mapping at the position it
437     * would have been inserted had the remove not occurred.
438     *
439     * @param index  the index at which the mapping should be inserted
440     * @param key  the key
441     * @param value  the value
442     * @return the value previously mapped to the key
443     * @throws IndexOutOfBoundsException if the index is out of range [0, size]
444     * @since 3.2
445     */
446    public V put(int index, final K key, final V value) {
447        if (index < 0 || index > insertOrder.size()) {
448            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + insertOrder.size());
449        }
450
451        final Map<K, V> m = decorated();
452        if (m.containsKey(key)) {
453            final V result = m.remove(key);
454            final int pos = insertOrder.indexOf(key);
455            insertOrder.remove(pos);
456            if (pos < index) {
457                index--;
458            }
459            insertOrder.add(index, key);
460            m.put(key, value);
461            return result;
462        }
463        insertOrder.add(index, key);
464        m.put(key, value);
465        return null;
466    }
7 голосов
/ 11 января 2014
public static <K, V> void add(LinkedHashMap<K, V> map, int index, K key, V value) {
  assert (map != null);
  assert !map.containsKey(key);
  assert (index >= 0) && (index < map.size());

  int i = 0;
  List<Entry<K, V>> rest = new ArrayList<Entry<K, V>>();
  for (Entry<K, V> entry : map.entrySet()) {
    if (i++ >= index) {
      rest.add(entry);
    }
  }
  map.put(key, value);
  for (int j = 0; j < rest.size(); j++) {
    Entry<K, V> entry = rest.get(j);
    map.remove(entry.getKey());
    map.put(entry.getKey(), entry.getValue());
  }
}
6 голосов
/ 30 октября 2012

Просто разделите вас LinkedHashMap на 2 массива. Создайте первый массив размером index - 1 и в конце добавьте новый Entry. Затем заполните первый массив записями из второго

1 голос
/ 02 мая 2018
...

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

map.put("4", new StringExtension("4", "a"));
map.put("1", new StringExtension("1", "b"));
map.put("3", new StringExtension("3", "c"));
map.put("2", new StringExtension("2", "d"));

for (Map.Entry<String, StringExtension> entry : map.entrySet()) {
    Log.e("Test", "" + entry.getKey() + " - "+ entry.getValue().value);
}


Collection<StringExtension> temp = new ArrayList<>(map.values());
StringExtension value = map.remove("3");
map.clear();
map.put(value.key, value);

for (StringExtension val : temp) {
    map.put(val.key, val);
}

Log.e("Test", "---");

for (Map.Entry<String, StringExtension> entry : map.entrySet()) {
    Log.e("Test", "" + entry.getKey() + " - "+ entry.getValue().value);
}

...

private class StringExtension
{
    String key;
    String value;

    public StringExtension(String key, String value) {
        this.key = key;
        this.value = value;
    }
}
1 голос
/ 07 октября 2011

Это Map, у него нет индексов. У него есть ведра. Это работает, когда вы делаете

put(key, val)

Он хеширует ключ, чтобы узнать, в какое ведро положить вал.

LinkedHashMap поддерживает двусвязный список, так что он может записывать порядок, в котором записи вставляются (или к которым обращаются, в зависимости от того, как вы создаете карту). В API на карте нет метода для вставки пары ключ, val в определенный индекс связанного списка, потому что это не та цель, которой он служит.

...