2010-01-22 107 views
3

通常,我有一個對象列表。每個對象都有屬性。我想提取特定屬性具有預定義值的列表的子集。基於對象屬性類型從列表中提取元素

例如:

我有一個User對象列表。用戶有一個homeTown。我想從我的列表中提取所有用戶作爲他們的homeTown的「Springfield」。

我通常看到這個實現如下:(

列表用戶= getTheUsers);

List returnList = new ArrayList();

爲(用戶用戶:用戶){

if ("springfield".equalsIgnoreCase(user.getHomeTown()) 

     returnList.add(user); 

}

我不是特別不滿意這個解決方案。是的,它有效,但它似乎很慢。必須有一個非線性的解決方案。

對此提出建議?

回答

0

我結束了使用謂詞。它的可讀性看起來與德魯的建議類似。

就性能而言,我發現對於小型(< 100個項目)列表可以忽略不計的速度改進。對於較大的清單(5k-10k),我發現有20-30%的改進。中等列表有好處,但不像更大的列表那麼大。我沒有測試超大型列表,但是我的測試顯示列表越大,與foreach過程相比結果越好。

0

正如我發現,如果你使用的是一個列表,你必須迭代。無論是for-each,lambda還是FindAll,它仍然在迭代中。無論你如何裝扮鴨子,它仍然是一隻鴨子。據我所知,有HashTables,Dictionaries和DataTables,不需要迭代來找到一個值。我不確定Java的等價實現是什麼,但也許這會給你一些其他的想法。

1

那麼,這個操作本質上是線性的,除非你做一些極端的事情,比如根據你希望以這種方式檢查的屬性來索引集合。簡而言之,你只需要查看集合中的每個對象。

但是可能有些事情可以提高可讀性。例如,Groovy爲集合提供了一個each() method。它可以讓你做這樣的事情...

def returnList = new ArrayList(); 
users.each() { 
    if ("springfield".equalsIgnoreCase(it.getHomeTown()) 
     returnList.add(user); 
}; 
1

你將需要一個自定義的解決方案。創建一個自定義集合,使其實現List接口並將原始列表中的所有元素添加到此列表中。

在這個自定義List類的內部,您需要維護一些Map所有屬性的集合,這些集合可以幫助您查找所需的值。要填充此地圖,您將不得不使用內省來查找所有字段及其值的列表。

此自定義對象將不得不實現一些方法,如List findAllBy(String propertyName, String propertyValue);將使用上面的哈希映射來查找這些值。

這不是一個簡單直接的解決方案。此外,您還需要考慮像「user.address.city」這樣的嵌套屬性。使這個自定義列表不可變將會有所幫助。

但是,即使您在List中迭代1000個對象的列表,它仍然會更快,因此您最好迭代List來滿足您的需求。

0

如果您對這裏的表現真的很感興趣,我還建議您使用定製解決方案。我的建議是創建一個列表樹您可以在其中排序元素。

如果您對列表中的元素排序不感興趣(並且大多數人通常不會),也可以使用TreeMap(或HashMap),並使用homeTown作爲鍵和所有條目的List作爲值。如果添加新元素,只需在Map中查找所屬列表並追加它(如果它是第一個元素,則需要首先創建列表)。如果你想刪除一個元素,只需執行相同的操作。

如果你想要一個給定homeTown的所有用戶的列表,你只需要在Map中查找這個列表並返回它(不需要複製所需的元素),但我並不是100%確定Map的實現在Java中,但完整的方法應該是恆定的(最壞情況下對數,取決於Map實現)。