【问题标题】:Comparing key and values of two java maps比较两个java映射的键和值
【发布时间】:2012-12-25 00:50:54
【问题描述】:

我对 Java 还比较陌生,我发现自己一直在尝试正确编写这段我觉得应该更简单的代码。

我有两张由同一对象的两个不同实例组成的地图。键是对象,值是对象。

有两个实例,因为我试图确定一个实例中的键是否与另一个实例中的键不同。我正在尝试专门定位新键或丢失的键,然后比较两个映射中存在的键的值。

下面的示例代码只是为了帮助可视化我正在尝试做的事情(希望它不会更令人困惑!)

下面示例的目标应该告诉我缺少键“C”并且有一个新键(“D”),然后它应该最终比较两个映射中键的值。

主要问题是,是否可以在一个循环中执行此操作?主要是因为我的实际代码将接触文件系统以获取地图中的值,并且我试图最小化它必须接触磁盘的时间

Map<objA, objB> mapA = new HashMap<objA, objB>();
mapA.put("A", "1");
mapA.put("B", "2");
mapA.put("C", "3");

Map<objA, objB> mapB = new HashMap<objA, objB>();
mapB.put("A", "1");
mapB.put("D", "4");

// Check if something is missing from mapB
for(Map.Entry<objA, objB> entryMapA:mapA.entrySet())
{
    if(!mapB.containsKey(entryMapA.getKey())
        {
            System.out.println(entryMapA.getKey() + " is missing");
        }
}

// Check if something is new is in mapB
for(Map.Entry<objA, objB> entryMapB:mapB.entrySet())
{
    if(!mapA.containsKey(entryMapB.getKey())
    {  
        System.out.println(entryMapB.getKey() + " is new");
    }
}

【问题讨论】:

标签: java map comparison


【解决方案1】:

Map 中的键是 Sets,因此您可以使用集合和可用的操作。

例如:

Set<String> keysInA = new HashSet<String>(mapA.keySet());
Set<String> keysInB = new HashSet<String>(mapB.keySet());

// Keys in A and not in B
Set<String> inANotB = new HashSet<String>(keysInA);
inANotB.removeAll(keysInB);

// Keys common to both maps
Set<String> commonKeys = new HashSet<String>(keysInA);
commonKeys.retainAll(keysInB);

等等等等

注意:您不得直接使用地图的键集。如果你这样做:

// This returns the actual key set of the map, NOT a copy!
Set<String> inANotB = mapA.keysSet();
inANotB.removeAll(mapB.keySet())

您实际上删除了mapA中的键(及其关联值)

最后,您应该注意HashSet 不做任何订单保证。如果这对您很重要,您可以查看SortedSet 的实现(例如TreeSet)。

【讨论】:

  • 请原谅我的无知,但是当您说“您不得直接使用映射的键集:它是可变的”时,我不明白。我还是编程新手,所以有些术语令人困惑……什么是可变的?
  • @nkon:Set 返回的.keySet() 是映射的实际键集。如果您修改该集合,您将修改地图本身。你可能不希望这样;)
  • @fge:如果您想在不更改原始地图的情况下对场景进行破坏性修改,您确实需要一个副本,但没有必要为每个场景制作 两个 副本就像你的代码一样。 (我意识到你这样做是因为每个变量都是它自己的副本。)这是一个函数式样式(返回新副本而不是 mutator 方法的纯函数)的示例,例如 Louis 在上面的评论中提到的 Guava 实用程序,导致更清晰的代码。
  • @DanielPryden 是的,我经常使用 Guava,但是 OP 使用它吗?如果是我,所有 Guava 都应该在 JDK 中(Joda Time 也是如此),但我该决定谁呢? ;)
  • 我以前听说过 Guava,但老实说,我对编程和 Java 非常陌生,所以我什至不知道如何使用 Guava,因为它似乎没有成为标准 API 的一部分。
【解决方案2】:

您可以减去键集:

Set<objA> keysA1 = new HashSet<objA>(mapA.keySet()); // deepcopy
Set<objA> keysA2 = new HashSet<objA>(mapA.keySet()); // deepcopy
Set<objB> keysB = new HashSet<objB>(mapB.keySet()); // deepcopy

keysA1.removeAll(keysB);
keysB.removeAll(keysA2);

System.out.println("Missing in A: " + keysB);
System.out.println("Missing in B: " + keysA1);

【讨论】:

  • 几乎 +1,但您的 // deepcopy cmets 充其量只是误导。 HashSet 构造函数只制作 shallow 副本。因为字符串是不可变的,所以在这里你可以侥幸逃脱,但如果集合中有可变对象,那么这些实例将在副本之间共享。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多