【问题标题】:How can I make a Map with two indexes?如何制作具有两个索引的地图?
【发布时间】:2015-08-22 02:50:27
【问题描述】:

我在 java 中有一张这样的地图:

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

我想通过使用index1index2 作为查找在地图中获取我的Object

【问题讨论】:

  • 您正确地声明了使用字符串作为键并将映射作为值的映射。您像往常一样使用Map.get() 来获取价值。由于该值是一个映射,因此您可以对其执行相同的操作。

标签: java hashmap


【解决方案1】:

如果您愿意使用第三方库,最简单的方法是使用 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


如果你不想使用 Guava,那你就有大问题了。如果您尝试使用新的第一个键插入元素,则必须确保内部映射已经存在。这意味着,每次您执行put 时,您都必须检索innerMap,查看它是否存在,如果不存在则创建它。 每次调用 Map.put 时都必须这样做。此外,如果在内部映射上调用 get 时内部映射不存在,则可能会抛出 NullPointerException

如果您这样做,应该将您的Map&lt;String, Map&lt;String, Object&gt; 包装在一个外部类中以管理这些问题,或者使用Java 8 的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);
  }
}

你可以通过这样做来使用这个类:

DoubleMap<String, String, Object> map = new DoubleMap();

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

【讨论】:

  • 所以 Elliot Frisch 的回答是错误的,因为他没有指定如何处理内部映射不存在的情况?虽然您是有效的,因为您说主要解决方案是使用外部库?我同意 Guava 应该被添加到任何重大项目中。但是,我认为 OP 并不是在寻求验证,而是寻求一个关于如何通过 Elliot Frisch 回答的两个索引检索地图的简单答案。提一下如何处理内部地图会是一个加分项,但这不是最初的OP的问题。
  • @Jean-FrançoisSavard 我正在做一个简单的实现。此外,内部映射不存在的情况经常发生,并且是问题的核心部分。
  • 虽然我仍然认为另一个答案是有效的,但为您的新编辑和您的乐高西斯个人资料图片 +1。
  • 将此评论标记为非建设性的,但您的个人资料显示您“其余时间都是乐高绝地”,但在您的个人资料图片上,您的剑是红色的:/
  • @Jean-FrançoisSavard 我没有说我是不是黑暗绝地:)
【解决方案2】:

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);

【讨论】:

  • @durron597,除非您使用的是 Java-8(在本例中为 map.computeIfAbsent("a", k -&gt; new HashMap&lt;&gt;()).put("b")
  • @TagirValeev 1. OP 没有说他们使用的是 Java 8。2. 答案中需要包含这些信息。
  • @Elliott 感谢您对我的支持。因此,我想将对象设置为按索引 1、索引 2 映射,我不知道该怎么做。帮助我。
  • @durron597 感谢和编辑,我欣赏 建设性批评。我希望它现在读起来更好。
  • 我删除了我的反对票,因为这个答案不再不正确;但是在实践中仍然很难使用。野兽的本性;除非您将所有行为包装在一个全新的类中,否则这个问题会导致大量样板代码。
【解决方案3】:

如果您不需要定期访问整个“行”,而只需要快速访问每个单元格,您可以使用内置的Map.Entry 作为您的密钥:

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

或者,如果您愿意使用第三方的东西,一些人已经为 Java 实现了tuples

如果你处于无法轻松拉入第三方库的情况,但又不喜欢Map.Entry 的语义(以keys 和values 的形式写成)你可以编写自己的Pair 类来达到同样的效果。

【讨论】:

  • 或者,如果你愿意使用第三方的东西,一些人已经为 Java 实现了tuples
  • Map.Entry 用于键/值对,而不用于键/键对。使用元组,或者在没有这些的情况下,自定义键类对我来说似乎更可取。
【解决方案4】:

据我了解,您可以这样做:

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

【讨论】:

  • 所以当我想通过 index1 和 index 2 设置时。你能帮帮我吗?在我的 Map 然后 Map 有很多相同的键。我想要,但 (index1, index2) 不同。
  • 设置索引是什么意思?!你想把 index1 和 index2 放到地图上吗?!或者你想从 index1 获取 Map,然后从 index2 获取 Object,然后从 index2 更改 Object?!
【解决方案5】:

最佳解决方案可能取决于此地图的用途:

  • 它是在有限范围内使用的,还是公共 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&lt;T&gt;Tuple&lt;S,T&gt;,但这似乎不是您一直在寻找的...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-11
    • 2021-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多