2010-10-22 5 views
2

Je cherche une structure de données de type Collection pour implémenter ce qui suit. Dire que j'ai une classe comme ceci:Collection avec plusieurs valeurs dans la clé

class Person() { 

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

    // other stuff.... 
} 

Je suis en train de traiter plusieurs objets personne. Je veux les organiser en ensembles dans lesquels chaque ensemble contient des objets Person avec les mêmes homeTown, sex et eyeColour. En ce moment je suis quelque chose comme ça la mise en œuvre:

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

où la clé est une concatanation du HomeTown, le sexe et couleur des yeux. Cela fonctionne mais semble un peu désordonné - quelqu'un peut-il suggérer une solution plus élégante ou une meilleure structure de données à utiliser, merci?

Répondre

4

Vous pourriez restructurer votre classe pour rendre la clé explicite. Cela est plus robuste que la simple concaténation des valeurs de clé et évite toute surcharge de création d'objet supplémentaire au moment où vous souhaitez stocker votre instance Person dans une carte, car vous avez déjà créé la clé avec impatience.

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; } 
} 
+0

oui, cela a du sens, merci – CodeClimber

+0

Je devrais aussi souligner que l'utilisation de chaînes pour des choses comme le sexe et eyeColour est probablement une mauvaise idée; vous devriez envisager d'utiliser des énumérations. De même, vous pouvez vouloir vérifier que la hauteur est non négative pendant l'instanciation et peut-être aussi la renommer en quelque chose d'explicite; par exemple. "heightInCentimetres". – Adamski

+0

C'est juste un exemple que j'ai inventé pour le bien de cette question mec! – CodeClimber

0

Vous pouvez utiliser la méthode guava's Sets.filter pour filtrer les objets de personne.

Exemple:

classe Personne:

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(); 
} 

} 

classe 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; 
} 

} 

L'avantage d'utiliser un filtre est que vous pouvez filtrer l'objet Personne de toute façon, supposons que vous voulez filtrer En utilisant uniquement la ville de résidence et pas les 2 autres attributs, cela vous sera utile. Plus d'infos car le filtre de goyave ne produit qu'une vue de l'ensemble réel, vous pouvez économiser de la mémoire.

+0

Merci Emil - je ne sais pas si cela me convient bien. Vous passez dans le nouveau FilterHomeTown ("NY") - Je cherche à regrouper des éléments qui ont la même homeTown, pas tous les éléments où le homeTown est "NY" ou "LA" ou autre chose. Ou ai-je mal compris? – CodeClimber

2

Créez un objet pour modéliser votre clé. Par exemple class PersonKey { String homeTown, sex, eyeColour } (les getters et setters sont omis par souci de brièveté)

Implémentez la méthode equals et hashCode pour cet objet.

Utilisez cet objet comme clé dans votre Map.

Supprimez les attributs de votre objet Person ou remplacez-les par une référence à votre objet PersonKey.

En outre, pensez à définir le type de votre carte, c'est-à-dire que vous n'avez pas besoin de spécifier le type de Set que vous utilisez comme clé de votre carte.

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

Et, si vous utilisez un Set<Person> alors vous aurez besoin de passer outre equals et hashCode pour le Person ainsi, sinon le Set ne peut pas déterminer correctement si deux Person objets représentent la même personne ou non, ce qui est nécessaire pour s'assurer que la collection ne contient que des éléments uniques.

+0

merci Adrian, même suggestion (plus ou moins) que Adamski que j'ai mis en œuvre – CodeClimber

0

org.apache.commons.collections.map.MultiValueMap

+0

Salut foret, merci pour la suggestion. J'ai regardé l'API pour ça. Je ne pense pas que ce soit ce que je cherche - il utilise une collection comme valeur de carte, mais cela ne me donne pas une meilleure façon d'implémenter la clé de la carte, ce que je demandais. Je pourrais l'utiliser avec la solution clé suggérée par Adamski et Adrian Smith, je suppose. – CodeClimber

Questions connexes