Java对象的多个HashCodes

时间:2016-02-22 06:52:32

标签: java group-by hashmap hashcode

我试图优化一些代码,当我这样做时,我通常最终会从Hash结构中获得帮助。

我想要做的是以非常快的方式基于某些属性将对象划分为多个集合。基本上像SQL GROUP BY语句,但对于Java。

问题是我想用HashMap<Object, ArrayList<Object>>来做这件事。我想使用多种分组方式,但Object只能有一个hashCode()

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

注意:我想要的hashCodes使用多个非常量的属性。因此,例如,创建一个表示这些属性的字符串是唯一无法工作的,因为我每次都必须刷新字符串。

3 个答案:

答案 0 :(得分:2)

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

对于下面的伪代码,我假设存在一个MultiMap类,它封装了地图的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);

答案 1 :(得分:1)

你所描述的内容听起来像是一个相当复杂的模式,可能还有premature optimization。您可能会更好地询问有关如何在Java中有效复制GROUP BY - 样式查询的问题。

这就是说拥有多个哈希码的最简单方法是拥有多个类。这是一个微不足道的例子:

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

通过使用包装类,您可以以类型安全的方式重新定义相等的概念。要小心你是如何让这些类型互动的;您只能将PersonPersonWrapper1PersonWrapper2的实例与同类型的其他实例进行比较;每个班级&#39;如果传入其他类型,.equals()方法应返回false

您还可以查看hashing utilities in Guava,它们提供了几种不同的散列函数以及BloomFilter实现,这是一种依赖于能够使用多个散列函数的数据结构。

这是通过将散列函数抽象为Funnel类来完成的。 Funnel - 有能力的类只是简单地将用于相等的值传递给Funnel,并且调用者(如BloomFilter)然后实际计算哈希码。

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

答案 2 :(得分:0)

考虑您的想法:

  

我想要做的是以非常快的方式基于某些属性将对象划分为多个集合。基本上类似于 SQL GROUP BY 语句,但对于Java。

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