我有一个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));