密钥中具有多个值的集合

时间:2010-10-22 09:51:11

标签: java collections

我正在寻找一个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的连接。这有效,但似乎有点凌乱 - 任何人都可以提出更优雅的解决方案或更好的数据结构,谢谢?

4 个答案:

答案 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)

为此对象实施equalshashCode方法。

将此对象用作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