38

我有一个LinkedHashMap(称为信息),其中包含名称/年龄(字符串/整数)对。如果我输入键,如何获得键/值的位置?例如,如果我LinkedHashMap看起来像这样{bob=12, jeremy=42, carly=21}并且我要搜索jeremy,它应该返回1位置 1。我希望我可以使用类似info.getIndex("jeremy").

4

7 回答 7

31

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.

于 2012-04-30T16:43:10.313 回答
21
int pos = new ArrayList<String>(info.keySet()).indexOf("jeremy")
于 2015-04-22T06:31:29.940 回答
4

我从这个问题的副本之一看到了一个建议

如何根据索引而不是键从 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);
    }

}
于 2019-08-19T03:08:38.463 回答
1

考虑到 LinkedHashMap 保持插入顺序,您可以像这样使用 keySet() 和 List.copyOf() (从 Java 10 开始)方法:

List<String> keys = List.copyOf( yourLinkedHashMap.keySet() );

System.out.println( keys.indexOf("jeremy") ); // prints '1'
于 2021-09-09T10:09:13.143 回答
0

LinkedHashMap 具有“可预测的迭代顺序”(javadoc)。但是,项目不知道它们的位置,因此您必须迭代集合才能获得它。如果您要维护大型地图,您可能希望使用不同的存储结构。

编辑:澄清迭代

于 2012-04-30T16:57:05.997 回答
0

您可以com.google.common.collect.LinkedListMultimapGoogle Guava library使用。您不需要此类的多映射行为您想要的是该keys()方法保证它们按插入顺序返回,然后可以用于构造一个 List,您可以使用indexOf()找到所需的索引位置

于 2014-09-08T17:51:21.613 回答
0

我确实将键的位置提取到这样的并发映射中:

对于 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));
于 2020-12-17T13:34:47.680 回答