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,您可以以类型安全的方式重新定义相等的概念。请注意让这些类型交互的具体方式;您只能将 Person
、PersonWrapper1
或 PersonWrapper2
的实例与其他相同类型的实例进行比较;每个 class' .equals()
方法应该 return false
如果传入不同的类型。
您还可以查看 hashing utilities in Guava, they provide several different hashing functions, along with a BloomFilter
实现,这是一种依赖于能够使用多个哈希函数的数据结构。
这是通过将哈希函数抽象为Funnel
class来完成的。 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())));
我正在尝试优化一些代码,当我这样做时,我通常最终会得到哈希结构的帮助。
我想做的是根据一些属性以非常快的方式将对象分成多个集合。基本上像 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,您可以以类型安全的方式重新定义相等的概念。请注意让这些类型交互的具体方式;您只能将 Person
、PersonWrapper1
或 PersonWrapper2
的实例与其他相同类型的实例进行比较;每个 class' .equals()
方法应该 return false
如果传入不同的类型。
您还可以查看 hashing utilities in Guava, they provide several different hashing functions, along with a BloomFilter
实现,这是一种依赖于能够使用多个哈希函数的数据结构。
这是通过将哈希函数抽象为Funnel
class来完成的。 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())));