Java 中的顺序无关哈希

问题描述 投票:0回答:3

我想用Java计算一组字符串的哈希值。是的,我可以对字符串进行排序并计算 使用

digest.update
进行 MD5 哈希迭代。 但我宁愿省略排序并使用类似
combineUnordered
https://github.com/google/guava/wiki/HashingExplained 有很多类似的问题提出相同的问题,例如Order-independent Hash Algorithm 但他们都没有提供一个简单的示例来展示如何在 Java 中迭代计算顺序无关的哈希值。

java hash set unordered
3个回答
6
投票

只需对每个哈希进行异或,顺序并不重要,而且哈希大小将是固定的,而不是随着集合的大小而增长。

使用内置java字符串哈希码的哈希码:

int hashcode = strings.stream()
        .mapToInt(Object::hashCode)
        .reduce(0, (left, right) -> left ^ right);

使用番石榴和MD5的哈希码就像所问的问题:

Optional<byte[]> hash = strings.stream()
        .map(s -> Hashing.md5().hashString(s, Charset.defaultCharset()))
        .map(HashCode::asBytes)
        .reduce((left, right) -> xor(left, right));


static byte[] xor(byte[] left, byte[] right) {
    if(left.length != right.length) {
        throw new IllegalArgumentException();
    }
    byte[] result = new byte[left.length];
    for(int i=0; i < result.length; i++) {
        result[i] = (byte) (left[i] ^ right[i]);
    }
    return result;
}

1
投票

您可以单独计算每个字符串的 MD5 哈希值,然后将它们全部相加以获得单个哈希值。这将是独立于顺序的。因为加法运算是可交换的。

这是一个示例(假设我们有一个方法 md5Hex(String str) 计算给定字符串的 md5 哈希值并以十六进制格式返回结果):

String[] strings = {"str1", "str2", "str3", ...};

BigInteger hashSum = BigInteger.ZERO;
for(String s : strings) {
    String hexHash = md5Hex(s);
    hashSum = hashSum.add(new BigInteger(hexHash, 16));
}

String finalHash = hashSum.toString(16);

0
投票

这是一个使用 Guava 计算一组字符串的顺序无关哈希的示例:

import java.util.Set;

import com.google.common.base.Charsets;
import com.google.common.hash.HashCode;
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing;

...

public String hash(final Set<String> strings) {
    final HashFunction function = Hashing.murmur3_128();

    // Hashing.combineUnordered will throw an exception if input is empty.
    if (strings.isEmpty()) {
        return function.newHasher()
            .hash()
            .toString();
    }

    final List<HashCode> stringsHashes = strings.stream()
            .map(string -> function.newHasher()
                    .putString(string, Charsets.UTF_8)
                    .hash())
            .toList();

    return Hashing.combineUnordered(stringsHashes).toString();
}
© www.soinside.com 2019 - 2024. All rights reserved.