我试图优化一些代码,当我这样做时,我通常最终会从Hash结构中获得帮助。
我想要做的是以非常快的方式基于某些属性将对象划分为多个集合。基本上像SQL GROUP BY语句,但对于Java。
问题是我想用HashMap<Object, ArrayList<Object>>
来做这件事。我想使用多种分组方式,但Object
只能有一个hashCode()
。
为了能够通过多种方法进行分组,有没有办法拥有多个hashCodes()
?是否有其他结构来解决这类问题?我可以使用Java 8 lambda表达式在hashCode()
参数中发送HashMap
吗?我傻了,有一种超快的方式,这不是很复杂吗?
注意:我想要的hashCodes使用多个非常量的属性。因此,例如,创建一个表示这些属性的字符串是唯一无法工作的,因为我每次都必须刷新字符串。
答案 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();
}
}
通过使用包装类,您可以以类型安全的方式重新定义相等的概念。要小心你是如何让这些类型互动的;您只能将Person
,PersonWrapper1
或PersonWrapper2
的实例与同类型的其他实例进行比较;每个班级&#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())));