如何使用两个索引制作地图?

时间:2015-08-22 02:50:28

标签: java hashmap

我在java中有一个这样的Map:

Map<String index1, Map<String index 2, Object obj>> map = new HashMap<>();

我希望使用Objectindex1作为查找来获取地图中的index2

5 个答案:

答案 0 :(得分:11)

如果您愿意使用第三方库,最简单的方法是使用Guava的Table

它的工作原理如下:

Table<String, String, Object> table = HashBasedTable.create();
table.put(index1, index2, obj);
Object retrievedObject = table.get(index1, index2);

您可以按照以下说明将其添加到项目中:How to add Guava to Eclipse project

如果你不想使用番石榴,你就会遇到大问题。如果您尝试使用新的第一个键插入元素,则必须确保内部映射已存在。这意味着,每次执行put时,您都必须检索innerMap,查看它是否存在,然后创建它(如果不存在)。 每次拨打Map.put时都必须执行此操作。此外,如果在调用{{1}时内部地图不存在,则可能会抛出NullPointerException在内部地图上。

如果您这样做,应将get包装在外部类中以管理这些问题,或使用Java 8的Map<String, Map<String, Object>。但最简单的方法是使用上面的computeIfAbsent

如果您使用自己的类而不是Table,那么它将类似于:

Table

您可以通过以下方式使用此课程:

public class DoubleMap<R, C, V> {
  private final Map<R, Map<C, V>> backingMap;

  public DoubleMap() {
    this.backingMap = new HashMap<>();
  }

  public V get(R row, C column) {
    Map<C, V> innerMap = backingMap.get(row);
    if(map == null) return null;
    else return innerMap.get(column);
  }

  public void put(R row, C column, V value) {
    Map<C, V> innerMap = backingMap.get(row);
    if(innerMap == null) {
      innerMap = new HashMap<C, V>();
      backingMap.put(row, innerMap);
    }
    innerMap.put(column, value);
  }
}

请注意,此答案的功能比Guava版本少得多。

答案 1 :(得分:7)

Map

获取值

如果我理解了您的问题,那么可能会使用索引ab(使用ternaryConditional Operator ? :防范null) ,

Object obj = (map.get("a") == null) ? null : map.get("a").get("b");

使用Generic Type

你可能更具体,比如

Map<String, Map<String, Something>> map = new HashMap<>();
Something s = (map.get("a") == null) ? null : map.get("a").get("b");

将值添加到Map

假设您要将Something value添加到map,可以使用类似的内容,

Map<String, Map<String, Something>> map = new HashMap<>();
if (map.get("a") == null) {
    map.put("a", new HashMap<>());
}
map.get("a").put("b", value);

答案 2 :(得分:5)

如果您不需要定期访问整个&#34;行&#34;,只需快速访问每个单元即可使用内置{{3} }作为你的钥匙:

Map<Map.Entry<String, String>, Object> table = new Map<>();
table.put(new Map.SimpleEntry("index1", "index2"), "Hello world");

或者,如果您愿意使用某些第三方,那么有些人已经为Java实施了Map.Entry

如果您处于无法轻松引入第三方库的情况,但您不喜欢Map.Entry的语义(根据key s编写和value s)你可以编写自己的Pair类来产生同样的效果。

答案 3 :(得分:2)

根据我的理解,你可以这样做:

Map<String, Map<String, Object> map= new HashMap();
Map<String, Object> subMap = map.get("index1");
if(subMap != null) {
    Object obj = subMap.get("index2");
}

答案 4 :(得分:2)

最佳解决方案可能取决于该地图的使用方式:

  • 是在有限的范围内使用,还是公共API的一部分?
  • “索引”始终是String类型,还是必须是通用的?
  • 它总是两个索引,或者您以后可能需要更多索引吗?
  • ...

一个实用的解决方案专注于您所描述的问题,即引入一个可用于索引的StringPair类。这样可以省去内部映射的2D查找(以及内部映射变空时可能的清理!),不需要任何第三方库,并且可读且高效。

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;

public class StringPairMapTest
{
    public static void main(String[] args)
    {
        Map<StringPair, Object> map = new LinkedHashMap<StringPair, Object>();

        map.put(StringPair.of("A","B"), 12);
        map.put(StringPair.of("C","D"), 34);

        System.out.println(map.get(StringPair.of("A","B")));
        System.out.println(map.get(StringPair.of("C","D")));
        System.out.println(map.get(StringPair.of("X","Y")));
    }
}

class StringPair
{
    private final String s0;
    private final String s1;

    static StringPair of(String s0, String s1)
    {
        return new StringPair(s0, s1);
    }

    private StringPair(String s0, String s1)
    {
        this.s0 = s0;
        this.s1 = s1;
    }

    @Override
    public String toString()
    {
        return "("+s0+","+s1+")";
    }

    @Override
    public int hashCode()
    {
        return Objects.hash(s0, s1);
    }

    @Override
    public boolean equals(Object obj)
    {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        StringPair other = (StringPair) obj;
        return Objects.equals(s0, other.s0) && Objects.equals(s1, other.s1); 
    }
}

当然,对Pair<T>Tuple<S,T>的推广是可能的,但这似乎不是您一直在寻找的......