我正在寻找一个Collection类型数据结构来实现以下功能。说我有这样的课程:
class Person() {
String homeTown; // key
String sex; // key
String eyeColour; // key
String name;
long height;
// other stuff....
}
我正在处理多个Person对象。我想将它们组织成集合,其中每个集合包含具有相同homeTown,sex和eyeColour的Person对象。目前我正在实施这样的事情:
Map<String, HashSet<Person>> = new HashMap<String, HashSet<Person>>;
其中关键是homeTown,sex和eyeColour的连接。这有效,但似乎有点凌乱 - 任何人都可以提出更优雅的解决方案或更好的数据结构,谢谢?
答案 0 :(得分:4)
您可以重新构建类以使密钥显式化。这比简单地连接键值更加健壮,并且当您希望将Person实例存储在Map中时避免任何额外的对象创建开销,因为您已经提前创建了密钥。
public class Person {
public class Key {
private final String homeTown;
private final String sex;
private final String eyeColour;
public Key(String homeTown, String sex, String eyeColour) { ... }
public boolean equals(Object o) { /* Override to perform deep equals. */ }
public int hashCode() { /* Could pre-compute in advance if the key elements never change. */ }
}
private final Key key;
private final String name;
private final long height;
public Person(String homeTown, String sex, String eyeColour, String name, long height) {
this.key = new Key(homeTown, sex, eyeColour);
this.name = name;
this.height = height;
}
public Key getKey() {
return key;
}
public String getName() { return name; }
public long getHeight() { return height; }
}
答案 1 :(得分:2)
创建一个对象来建模您的密钥。例如class PersonKey { String homeTown, sex, eyeColour }
(为了简洁省略了getter和setter)
为此对象实施equals
和hashCode
方法。
将此对象用作Map
。
从Person
对象中删除属性,或将其替换为对PersonKey
对象的引用。
此外,请考虑将地图类型设为以下内容,即您无需指定使用的Set
类型作为地图的关键字。
Map<String, Set<Person>> = new HashMap<String, Set<Person>>();
而且,如果您使用Set<Person>
,那么您还需要覆盖equals
的{{1}}和hashCode
,否则Person
无法正确确定两个Set
对象是否代表同一个人,这是确保集合仅包含唯一元素所必需的。
答案 2 :(得分:0)
您可以使用guava's Sets.filter方法过滤人物对象。
示例:的
人员类:
public class Person {
String name;
String hometown;
int age;
public Person(String name, String hometown, int age) {
this.name = name;
this.age = age;
this.hometown = hometown;
}
@Override
public int hashCode() {
int hash = 17;
hash = 37 * hash + name.hashCode();
hash = 37 * hash + hometown.hashCode();
hash = 37 * hash + age;
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
Person p;
if (obj instanceof Person)
p = (Person) obj;
else
return false;
if (this.name.equals(p.name) && this.hometown.equals(p.hometown)
&& this.age == p.age)
return true;
return false;
}
@Override
public String toString() {
StringBuilder b = new StringBuilder();
b.append("[name = ").append(name).append("\n");
b.append("home town = ").append(hometown).append("\n");
b.append("age = ").append(age).append("]");
return b.toString();
}
}
TestGuavaFilter类:
public class TestGuavaFilter {
public static void main(String[] args) {
Set<Person> set = new HashSet<Person>();
set.add(new Person("emil", "NY", 24));
set.add(new Person("Sam", "NY", 50));
set.add(new Person("george", "LA", 90));
System.out.println(Sets.filter(set, new FilterHomeTown("NY")));
}
}
class FilterHomeTown implements Predicate<Person> {
String home;
public FilterHomeTown(String home) {
this.home = home;
}
@Override
public boolean apply(Person arg0) {
if (arg0.hometown.equals(this.home))
return true;
return false;
}
}
使用过滤器的优点是你可以以任何方式过滤Person对象,假设你只想使用home-town过滤而不是其他2个属性,这将有用。更多,因为guava的过滤器只生成一个视图真正的Set,你可以节省内存。
答案 3 :(得分:0)
org.apache.commons.collections.map.MultiValueMap