【问题标题】:Comparing java maps via hashing通过散列比较java映射
【发布时间】:2011-10-09 17:29:11
【问题描述】:

我想比较两个 Java Maps 通过一个简单的哈希。

每个对象都在不同的计算机上,因此通过网络发送散列会比发送整个对象进行比较更便宜。

例如,我有两个 HashMaps 的 ExampleClass

Map<String,ExampleClass> One=new ...;

Map<String,ExampleClass> Other=new ...;

我不需要确保所有元素都相等我相信哈希就足够了。

我正要在每一侧进行迭代并创建一个“自制哈希”,然后将其发送到网络以最后比较例如int 或其他东西。

如果每次从集合中添加或删除对象时都计算这个“哈希”会很棒,这样我就不用迭代整个对象了。我必须封装Map 的每个添加/删除。有没有这样的 Java 库?

【问题讨论】:

  • 您是否在 Map 对象本身上尝试过 Object.hashCode()?
  • 您需要对自己的答案有多大把握?如果您需要“好的”精度级别,这里提到的每个人都提到的 Object.hashCode 可能会很好,但是哈希冲突可能而且确实会发生!如果您需要更高级别的检测,您可以考虑使用加密哈希,例如 SHA-512。
  • Eric 我认为这就是真实性提出的答案@Steven“好的”准确性水平还可以=)它是为了使用网络地图保持本地地图更新(以预期临时(但更慢)更新以防哈希失败)

标签: java collections hash comparison compare


【解决方案1】:

如果您的所有类都实现了hashCode()(不使用"default" memory address hashcode),您可以使用map's hashCode()

这里需要注意的是,如果您的 ExampleClass 没有实现 hashCode(),那么相等的项目可能在两台不同的机器上具有不同的哈希值,这将导致映射的哈希值不同。


澄清一下:

Map 实现了一个hashCode(),它被定义为Map.EnytryhashCode()s 的sum

Map.Entry's hashCode() 定义为键的hashCode() 和值的hashCode()xor。 你的键是Strings——它们有一个明确定义的hashCode()(两个相等的字符串总是有相同的hashCode())。 您的值是ExampleClass 实例——它们还需要一个明确定义的hashCode()

总而言之,包含{ s1 -&gt; ec1, s2 -&gt; ec2 } 的地图的哈希码等于:

(s1.hashCode() ^ ec1.hashCode()) + (s2.hashCode() ^ ec2.hashCode())

意味着它取决于ExampleClasshashCode()

如果ExampleClass 确实以等于ExampleClasses 和hashCode()s 的方式实现hashCode(),那么一切都会运行良好。 如果ExampleClass 没有实现hashCode(),它将使用ObjecthashCode(),这几乎总是会给你不同的hashCodes()

【讨论】:

  • 如果您存储在 Map 中的类实现了 hashCode,并且您使用的 Map 扩展了 AbstractMap,那么文档提供了必要的快乐。 “地图的哈希码定义为地图的 entrySet() 视图中每个条目的哈希码之和。”
  • ptomli 和真相..,据我所知,你说我必须实现 hashCode(),就像在@stefan 回答中一样,但同时,你说我可以“使用”地图的 hashCode( ),这让我有点困惑
  • 我在编辑中扩展了详细信息。您不需要为Map 重新实现哈希码——它已经正确实现了hashCode()。您确实需要为您放入地图的自定义类实现hashCode()(您的ExampleClass)。 (即使您同意 stefan 的回答,您也需要这样做)
【解决方案2】:

一个简单的解决方案就是对地图中每个对象的哈希值进行异或运算,或者对其进行一些简单的推导。因为对于所有 a 和 b,a ^ a = 0a ^ b ^ a = b,(xor 是可交换的、关联的,并且它自己的逆),并且由于 xor 很便宜,所以您的 add 和 remove 可以只对添加的(可能派生的)哈希码进行异或或已删除的项目。

您可能希望使用派生的哈希值来避免映射具有所有相同键和值但它们之间的某些映射被转置的情况。一个简单的派生哈希可能是key.hashCode() - value.hashCode(),这样可以避免大多数情况。

因此,您的代码可能如下所示:

public class MyMap<K, V> extends HashMap<K, V>{
    private int hash = 0;
    @Override
    public int hashCode() {return hash;}
    @Override
    public V put(K key, V value) {
        V old = super.put(key, value);
        if (old != null) this.hash ^= key.hashCode() - old.hashCode();
        this.hash ^= key.hashCode() - value.hashCode();
        return ret;
    }
    @Override
    public V remove(K key) {
        V ret = super.remove(key);
        if (ret != null) this.hash ^= key.hashCode() - ret.hashCode();
        return ret;
    }
}

请注意,一些更高级的方法(例如,从集合中添加多个项目)可能安全,也可能不安全,具体取决于实现。

【讨论】:

  • 当添加多个项目时迭代整个 Map 是可以理解的,但对于单个添加/删除则不行,尽管我会使用其他哈希,这似乎是覆盖放置/删除方法的好方法。跨度>
  • 这是一个很好的优化,因为它更新哈希码,而不是每次调用hashCode() 时重新计算它。尽管我建议您遵守接口文档中给出的hashCode 的定义(xor 的总和),但也可以通过这种方式实现。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-04
  • 2019-07-12
  • 2014-11-04
  • 1970-01-01
  • 2022-10-13
  • 2013-06-04
相关资源
最近更新 更多