Java 个对象的多个哈希码

Multiple HashCodes for Java Objects

我正在尝试优化一些代码,当我这样做时,我通常最终会得到哈希结构的帮助。

我想做的是根据一些属性以非常快的方式将对象分成多个集合。基本上像 SQL GROUP BY 语句但是 Java.

问题是我想使用 HashMap<Object, ArrayList<Object>> 来执行此操作。我想使用多种分组方式,但一个 Object 只能有一个 hashCode().

有没有办法拥有多个 hashCodes() 以便能够通过多种方法进行分组?是否有其他结构来解决此类问题?我可以使用 Java 8 个 lambda 表达式在 HashMap 参数中发送一个 hashCode() 吗?我是不是傻了,有没有这么复杂的超快速方法?

注意:我想要的哈希码使用了多个不是常量的属性。因此,例如,创建一个唯一表示这些属性的字符串是行不通的,因为我每次都必须刷新字符串。

您所描述的内容听起来像是一个相当复杂的模式,并且可能是 premature optimization。你可能会问一个关于如何在 Java.

中有效地复制 GROUP BY 式查询的问题

也就是说,拥有多个哈希码的最简单方法是拥有多个 classes。这是一个简单的例子:

public class Person {
  String firstName;
  String lastName;

  /** the "real" hashCode() */
  public int hashCode() {
    return firstName.hashCode() + 1234 * lastName.hashCode();
  }
}

public class PersonWrapper1 {
  Person person;

  public int hashCode() {
    return person.firstName.hashCode();
  }
}

public class PersonWrapper2 {
  Person person;

  public int hashCode() {
    return person.lastName.hashCode();
  }
}

通过使用包装器 classes,您可以以类型安全的方式重新定义相等的概念。请注意让这些类型交互的具体方式;您只能将 PersonPersonWrapper1PersonWrapper2 的实例与其他相同类型的实例进行比较;每个 class' .equals() 方法应该 return false 如果传入不同的类型。


您还可以查看 hashing utilities in Guava, they provide several different hashing functions, along with a BloomFilter 实现,这是一种依赖于能够使用多个哈希函数的数据结构。

这是通过将哈希函数抽象为Funnelclass来完成的。 Funnel-able classes 简单地通过管道将它们用于相等的值输入 Funnel,然后调用者(如 BloomFilter)实际计算哈希码。


你的最后一段令人困惑;您不能希望将对象存储在基于散列的数据结构中,然后然后 更改用于计算散列码的值。如果这样做,将无法再在数据结构中发现该对象。

假设您有一个对象集合,您想要生成类似于 SQL GROUP BY 的不同分组。每个分组依据都由一组公共值定义。为每个不同的分组类型创建一个 group-by-key class,每个分组类型都有一个适当的 hashCode()equals() 方法(根据 Map 合同的要求)。

对于以下伪代码,我假设存在 MultiMap class,它封装了地图 List<Object> 值的管理。您可以使用 Guava 的 MultiMap 实现。

// One group key
public class GroupKey1 {
    ...
    public GroupKey1(MyObject o) {
        // populate key from object
    }
    public GroupKey1(...) {
        // populate from individual values so we can create lookup keys
    }
    public int hashCode() { ... }
    public boolean equals() { ... }
}

// A second, different group key
public class GroupKey2 {
    ...
    public GroupKey2(MyObject o) {
        // populate key from object
    }
    public GroupKey2(...) {
        // populate from individual values so we can create lookup keys
    }
    ...
}
...
MultiMap<GroupKey1,MyObject> group1 = new HashMultiMap<>();
MultiMap<GroupKey2,MyObject> group2 = new HashMultiMap<>();

for (MyObject m : objectCollection)
{
    group1.put(new GroupKey1(m), m);
    group2.put(new GroupKey2(m), m);
}
...
// Retrieve the list of objects having a certain group-by key
GroupKey2 lookupKey = new Groupkey2(...);
Collection<MyObject> group = group2.get(lookupKey);

考虑到您的想法:

What I want to do is divide objects into multiples sets based on some attributes in a very fast way. Basically like SQL GROUP BY statement but for Java.

Map<City, Set<String>> lastNamesByCity
     = people.stream().collect(groupingBy(Person::getCity,
                                          mapping(Person::getLastName, toSet())));