我有一个有序的LinkedHashMap,我想在特定索引处添加元素,比如在地图中的第一个位置或最后一个位置。 如何在LinkedHashMap中的特定位置添加元素?
即使我可以将一个元素添加到LinkedHashMap中的FIRST或LAST位置也会有帮助!
答案 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)
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
,或违反将军的类似地图 合同Map
。ListOrderedMap
(或更确切地说,是。{1}} 基础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 }
答案 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); }