如何在LinkedHashMap中的特定索引/位置添加元素?

时间:2011-10-06 20:01:57

标签: java collections linkedhashmap

我有一个有序的LinkedHashMap,我想在特定索引处添加元素,比如在地图中的第一个位置或最后一个位置。 如何在LinkedHashMap中的特定位置添加元素?

即使我可以将一个元素添加到LinkedHashMap中的FIRST或LAST位置也会有帮助!

9 个答案:

答案 0 :(得分:20)

您无法更改订单。这个构造函数是insert-order(默认情况下)或access-order

  

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

     
      
  • 使用指定的初始容量,加载因子和排序模式构造一个空的LinkedHashMap实例。

  •   
  • 参数:       initialCapacity - 初始容量       loadFactor - 加载因子       accessOrder - 排序模式 - 对于访问顺序为true,对于插入顺序为false

  •   
  • 抛出:       IllegalArgumentException - 如果初始容量为负数或负载因子为非正数

  •   

请参阅:LinkedHashMap

答案 1 :(得分:18)

您可以将此元素添加到1.或最后一个位置:

添加到上一个位置►您只需要从地图中删除上一个条目,如下所示:

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

添加到第一位►这有点复杂,你需要克隆地图,清除它,将1.值放到它上面,并将新地图放到它上面,如下所示:

我正在使用带有字符串键和Group(我的自定义类)值的地图:

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

如您所见,使用这些方法,您可以在地图的开头和结尾添加无限量的内容。

答案 2 :(得分:9)

Apache Commons解决方案:ListOrderedMap

由于JDK LinkedHashMap仅确保插入顺序检索,如果我们想要在索引处插入,我们可以使用Apache Commons'ListOrderedMap。它听起来就是这样 - 通过一个列表来维护插入的顺序,使用相应的索引和普通的地图来插入,就像我们通常那样。以下是docs所说的内容:

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

装饰Map以确保保留添加顺序   使用List来维持秩序。

     

订单将通过迭代器和toArray方法使用   观点。该订单也由MapIterator返回。该   orderedMapIterator()方法访问可以迭代的迭代器   向前和向后穿过地图。此外,   提供非接口方法以通过索引访问地图。

     

如果某个对象第二次添加到地图中,它将保留在   迭代中的原始位置。

     

请注意ListOrderedMap未同步且不是线程安全的。   如果您希望同时使用多个线程中的此映射,那么   必须使用适当的同步。最简单的方法是包装   此地图使用Collections.synchronizedMap(Map)。这堂课可能会   在没有的并发线程访问时抛出异常   同步。

     

请注意,ListOrderedMap不适用于IdentityHashMap,   CaseInsensitiveMap,或违反将军的类似地图   合同MapListOrderedMap(或更确切地说,是。{1}}   基础List)依赖equals()。这很好,只要   装饰Map也基于equals()hashCode(),   其中IdentityHashMapCaseInsensitiveMap没有:前者   使用==,后者在较低的密钥上使用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    }

答案 3 :(得分:6)

只需在{2}数组上划分LinkedHashMap。制作尺寸为index - 1的第一个数组,并将结尾放在新的Entry。然后用第二个数据填入第一个数组

答案 4 :(得分:6)

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());
  }
}

答案 5 :(得分:1)

它是Map,它没有索引。它有水桶。它的工作方式是你做一个

put(key, val)

它是找出将val放入哪个桶的关键。

LinkedHashMap维护一个双向链表,以便它可以记录插入(或访问条目的顺序,具体取决于您实例化地图的方式)。在Map上的API上没有方法在链表的某个索引处插入键,val对,因为这不是它所服务的目的。

答案 6 :(得分:1)

...

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;
    }
}

答案 7 :(得分:0)

如在其他答案中所建议的那样,当然不建议这样做,因为插入值将对系统不利。

为什么?
因为LinkedHashMap由HashMap和LinkedList支持。
最后一个用于保留插入顺序。
显然,LinkedList在插入头部和故事时(双链接)非常好。 它为该操作提供了O(1)时间复杂度。
但是,插入到某个位置的速度非常慢,因为要找到该位置,您需要遍历整个列表,在最坏的情况下,这将花费O(n),这对于大型数据集而言尤其昂贵。

我个人不建议这样做,因为它效率很低, 但是如果您了解缺点,这就是您想要的,
您可以使用此扩展功能来将密钥对插入到特定位置

fun <K, V> LinkedHashMap<K, V>.insertAtIndex(key: K, value: V, index: Int) {
    if (index < 0) {
        throw IllegalArgumentException("Cannot insert into negative index")
    }
    if (index > size) {
        put(key, value)
        return
    }
    val holderMap = LinkedHashMap<K, V>(size + 1)
    entries.forEachIndexed { i, entry->
        if (i == index) {
            holderMap.put(key, value)
        }
        holderMap.put(entry.key, entry.value)
    }
    clear()
    putAll(holderMap)
}

这将花费O(n)时间和O(n)空间。

答案 8 :(得分:0)

假设应用于 Map 的数据来自 List(集合),那么您应该创建一个反向循环,从它的末尾开始读取列出直到它到达第一个像这样: for (int key = collection.size()-1; key > map.size(); key--) { Data data = collection.get(key); map.put(key, data); }