我有一个LinkedHashMap
(称为信息),其中包含名称/年龄(字符串/整数)对。如果我输入键,如何获得键/值的位置?例如,如果我LinkedHashMap
看起来像这样{bob=12, jeremy=42, carly=21}
并且我要搜索jeremy
,它应该返回1
位置 1。我希望我可以使用类似info.getIndex("jeremy")
.
7 回答
HashMap
一般来说,实现是无序的Iteration
。
LinkedHashMap
可预测地为Iteration
(插入顺序)排序,但不公开List
接口,并且 a LinkedList
(这反映了键集插入顺序)本身也不跟踪索引位置,查找索引也非常低效。LinkedHashMap
也不公开对内部的引用LinkedList
。
实际的“链接列表”行为是特定于实现的。有些人可能实际上使用了
LinkedList
一些实例,其中许多只是Entry
跟踪前一个和下一个Entry
并将其用作其实现。不看源头就不要假设任何事情。
包含键的KeySet
也不能保证顺序,因为散列算法用于放置在继承的支持数据结构中HashMap
。所以你不能使用它。
在不编写自己的实现的情况下执行此操作的唯一方法是遍历Iterator
使用镜像的对象LinkedList
并记录您所在的位置,这对于大型数据集将非常低效。
解决方案
听起来您想要的是原始插入顺序索引位置,您必须镜像 in 中的键,KeySet
例如 an ArrayList
,使其与更新同步HashMap
并使用它来查找位置。创建一个子类HashMap
,比如说IndexedHashMap
并在内部添加这个,然后在ArrayList
内部添加一个.getKeyIndex(<K> key)
代表ArrayList
.indexOf()
可能是解决这个问题的最好方法。
这就是所做LinkedHashMap
的,但使用LinkedList
镜像KeySet
而不是ArrayList
.
int pos = new ArrayList<String>(info.keySet()).indexOf("jeremy")
我从这个问题的副本之一看到了一个建议
如何根据索引而不是键从 LinkedHashMap 获取值?
我喜欢评论中@schippi 中描述为伪代码的建议。我认为一些有效的 Java 代码可能对其他人有用
import java.util.ArrayList;
import java.util.LinkedHashMap;
public class IndexedLinkedHashMap<K,V> extends LinkedHashMap<K,V> {
/**
*
*/
private static final long serialVersionUID = 1L;
ArrayList<K> al_Index = new ArrayList<K>();
@Override
public V put(K key,V val) {
if (!super.containsKey(key)) al_Index.add(key);
V returnValue = super.put(key,val);
return returnValue;
}
public V getValueAtIndex(int i){
return (V) super.get(al_Index.get(i));
}
public K getKeyAtIndex(int i) {
return (K) al_Index.get(i);
}
public int getIndexOf(K key) {
return al_Index.indexOf(key);
}
}
考虑到 LinkedHashMap 保持插入顺序,您可以像这样使用 keySet() 和 List.copyOf() (从 Java 10 开始)方法:
List<String> keys = List.copyOf( yourLinkedHashMap.keySet() );
System.out.println( keys.indexOf("jeremy") ); // prints '1'
LinkedHashMap 具有“可预测的迭代顺序”(javadoc)。但是,项目不知道它们的位置,因此您必须迭代集合才能获得它。如果您要维护大型地图,您可能希望使用不同的存储结构。
编辑:澄清迭代
您可以com.google.common.collect.LinkedListMultimap
从Google Guava library使用。您不需要此类的多映射行为您想要的是该keys()
方法保证它们按插入顺序返回,然后可以用于构造一个 List,您可以使用indexOf()
找到所需的索引位置
我确实将键的位置提取到这样的并发映射中:
对于 Map,someListOfComplexObject() 将是 entrySet(),而 getComplexStringKeyElem() 将是 getKey()
可能来自
final int[] index = {0};
Stream<ComplexObject> t = someListOfComplexObject.stream();
ConcurrentMap<String, List<Integer>> m =
t.collect(Collectors.groupingBy(
e -> e.getComplexStringKeyElem(),
Collectors.mapping(
e -> index[0]++,
Collectors.toList()
),
ConcurrentSkipListMap::new));