2010-10-22 71 views
2

我正在尋找一個集合類型數據結構來實現以下功能。假設我有這樣的課程:具有多個值的密鑰集合

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 concavanation。這工作,但似乎有點不整潔 - 任何人都可以建議一個更優雅的解決方案或更好的數據結構來使用,謝謝?

回答

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

是的,這是有道理的,謝謝 – CodeClimber 2010-10-22 15:39:33

+0

我還應該指出,使用字符串像性和eyeColour的東西可能是一個壞主意;你應該考慮使用枚舉。同樣,您可能想要在實例化時檢查高度是否定的,也可能將其重命名爲明確的;例如「heightInCentimetres」。 – Adamski 2010-10-22 15:44:14

+0

這只是我爲了這個問題而編造的一個例子! – CodeClimber 2010-10-22 15:56:25

0

您可以使用guava's Sets.filter方法來過濾person對象。

實施例:

Person類:

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對象在任何方式,假設你想過濾呃只使用家鄉,而不是其他2個屬性,這將有所幫助。因爲番石榴的過濾器只會產生一個真實的Set的視圖,所以您可以節省內存。

+0

謝謝埃米爾 - 不知道這是否適合我。你正在傳遞新的FilterHomeTown(「NY」) - 我正在尋找將具有相同homeTown的元素分組在一起,而不是homeTown爲「NY」或「LA」等的所有元素。或者我誤解了? – CodeClimber 2010-10-22 15:51:32

2

創建一個對象來建模您的密鑰。例如class PersonKey { String homeTown, sex, eyeColour }(爲簡潔起見省略了吸氣劑和吸附劑)

對此對象實施equalshashCode方法。

將此對象用作Map中的鍵。

從您的Person對象中刪除屬性或將其替換爲對PersonKey對象的引用。

此外,考慮將地圖的類型設置爲以下內容,即不需要指定使用哪種類型的Set作爲地圖的關鍵字。

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

而且,如果你使用的是Set<Person>,那麼你就需要重寫的PersonequalshashCode爲好,否則Set不能正確判斷兩個Person對象表示同一人或沒有,這是需要確保集合只包含獨特的元素。

+0

謝謝艾德里安,同樣的建議(或多或少),因爲我已經實施了亞當斯基 – CodeClimber 2010-10-22 15:40:32

0

org.apache.commons.collections.map。MultiValueMap

+0

嗨,先生,謝謝你的建議。看看這個API。我不認爲這是我在尋找的東西 - 它使用一個Collection作爲Map值,但它並沒有給我一個更好的方式來實現我所問的Map鍵。我可以將它與Adamski和Adrian Smith提出的關鍵解決方案一起使用。 – CodeClimber 2010-10-22 15:46:02