2010-01-22 40 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实现)。