Коллекция с несколькими значениями в ключе - PullRequest
2 голосов
/ 22 октября 2010

Я ищу структуру данных типа Collection для реализации следующего.Скажем, у меня есть такой класс:

class Person() {

    String homeTown;   // key
    String sex;  // key 
    String eyeColour;  // key
    String name;
    long height;

    // other stuff....
}

Я обрабатываю несколько объектов Person.Я хочу организовать их в наборы, в которых каждый набор содержит объекты Person с одинаковым homeTown, sex и eyeColour.На данный момент я реализую что-то вроде этого:

Map<String, HashSet<Person>> = new HashMap<String, HashSet<Person>>;

, где ключ - конкатенация homeTown, sex и eyeColour.Это работает, но кажется немного неопрятным - кто-нибудь может предложить более элегантное решение или лучшую структуру данных для использования, спасибо?

Ответы [ 4 ]

4 голосов
/ 22 октября 2010

Вы можете реструктурировать свой класс, чтобы сделать ключ явным. Это более надежно, чем простая конкатенация значений ключей, и позволяет избежать дополнительных затрат на создание объекта в тот момент, когда вы хотите сохранить экземпляр Person на карте, поскольку вы с нетерпением заранее создали ключ.

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; }
}
2 голосов
/ 22 октября 2010

Создайте объект для моделирования вашего ключа.Например, class PersonKey { String homeTown, sex, eyeColour } (методы получения и установки для краткости опущены)

Реализация метода equals и hashCode для этого объекта.

Используйте этот объект в качестве ключа в вашем Map.

Либо удалите атрибуты из вашего Person объекта, либо замените их ссылкой на ваш PersonKey объект.

Кроме того, рассмотрите возможность сделать тип вашей карты следующим, т.е. выне нужно указывать тип Set, который вы используете в качестве ключа к вашей карте.

Map<String, Set<Person>> = new HashMap<String, Set<Person>>();

И, если вы используете Set<Person>, вам придется переопределить equals и hashCode для Person, в противном случае Set не может правильно определить, представляют ли два объекта Person одно и то же лицо или нет, что необходимо для того, чтобы коллекция содержала только уникальные элементы.

0 голосов
/ 22 октября 2010

org.apache.commons.collections.map.MultiValueMap

0 голосов
/ 22 октября 2010

Вы можете использовать метод guava 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 class:

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 любым способом, предположим, что вы хотитеФильтровать только используя родной город, а не 2 других атрибута, это будет полезно. Более того, поскольку фильтр guava создает только представление реального набора, вы можете сэкономить память.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...