简体   繁体   English

根据对象属性类型从列表中提取元素

[英]Extract elements from list based on object property type

Often, I have a list of objects. 通常,我有一个对象列表。 Each object has properties. 每个对象都有属性。 I want to extract a subset of the list where a specific property has a predefined value. 我想提取列表的一个子集,其中特定属性具有预定义的值。

Example: 例:

I have a list of User objects. 我有一个User对象列表。 A User has a homeTown. 用户有一个homeTown。 I want to extract all users from my list with "Springfield" as their homeTown. 我想从我的列表中提取所有用户,将“Springfield”作为他们的homeTown。

I normally see this accomplished as follows: 我通常看到这完成如下:

List users = getTheUsers(); List users = getTheUsers();

List returnList = new ArrayList(); List returnList = new ArrayList();

for (User user: users) { for(用户user:users){

  if ("springfield".equalsIgnoreCase(user.getHomeTown()) returnList.add(user); 

} }

I am not particularly satisfied with this solution. 我对这个解决方案并不是特别满意。 Yes, it works, but it seems so slow. 是的,它有效,但似乎很慢。 There must be a non-linear solution. 必须有非线性解决方案。

Suggestions? 建议?

Well, this operation is linear in nature unless you do something extreme like index the collection based on properties you expect to examine in this way. 好吧,这个操作本质上是线性的,除非你根据你希望以这种方式检查的属性做一些极端的事情,比如索引集合。 Short of that, you're just going to have to look at each object in the collection. 除此之外,您只需要查看集合中的每个对象。

But there may be some things you can do to improve readability. 但是,您可以采取一些措施来提高可读性。 For example, Groovy provides an each() method for collections. 例如,Groovy为集合提供了each()方法 It would allow you to do something like this... 它可以让你做这样的事......

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

You will need a custom solution for this. 您需要一个自定义解决方案。 Create a custom collection such that it implements List interface and add all elements from original list into this list. 创建自定义集合,使其实现List接口,并将原始列表中的所有元素添加到此列表中。

Internally in this custom List class you need to maintain some collections of Map of all attributes which can help you lookup values as you need. 在这个自定义List类的内部,您需要维护一些Map的所有属性集合,这些集合可以帮助您根据需要查找值。 To populate this Map you will have to use introspection to find list of all fields and their values. 要填充此Map,您必须使用内省来查找所有字段及其值的列表。

This custom object will have to implement some methods as List findAllBy(String propertyName, String propertyValue); 这个自定义对象必须实现一些方法,如List findAllBy(String propertyName, String propertyValue); that will use above hash map to look up those values. 将使用上面的哈希映射来查找这些值。

This is not an easy straightforward solution. 这不是一个简单直接的解决方案。 Further more you will need to consider nested attributes like "user.address.city". 您还需要考虑嵌套属性,如“user.address.city”。 Making this custom List immutable will help a lot. 使这个自定义列表不可变将有很大帮助。

However even if you are iterating list of 1000's of objects in List, still it will be faster so you are better off iterating List for what you need. 但是,即使您在List中迭代1000个对象的列表,它仍然会更快,因此您最好根据需要迭代List。

I ended up using Predicates. 我最终使用了Predicates。 Its readability looks similar to Drew's suggestion. 它的可读性与Drew的建议类似。

As far as performance is concerned, I found negligible speed improvements for small (< 100 items) lists. 就性能而言,我发现小型(<100项)列表的速度改进可以忽略不计。 For larger lists (5k-10k), I found 20-30% improvements. 对于较大的列表(5k-10k),我发现了20-30%的改进。 Medium lists had benefits but not quite as large as bigger lists. 媒体列表有好处但不如大列表那么大。 I did not test super large lists, but my testing made it seem the large the list the better the results in comparison to the foreach process. 我没有测试超级大型列表,但是我的测试使得它看起来越大,与foreach过程相比结果越好。

As I have found out, if you are using a list, you have to iterate. 正如我所知,如果您使用的是列表,则必须进行迭代。 Whether its a for-each, lambda, or a FindAll - it is still being iterated. 无论是for-each,lambda还是FindAll - 它仍然是迭代的。 No matter how you dress up a duck, it's still a duck. 不管你怎么装扮鸭子,它仍然是一只鸭子。 As far as I know there are HashTables, Dictionaries, and DataTables that do not require iteration to find a value. 据我所知,有HashTables,Dictionaries和DataTables不需要迭代来查找值。 I am not sure what the Java equivalent implementations are, but maybe this will give you some other ideas. 我不确定Java等效实现是什么,但也许这会给你一些其他的想法。

If you are really interested in performance here, I would also suggest a custom solution . 如果您对这里的性能非常感兴趣,我还建议您使用自定义解决方案 My suggestion would be to create a Tree of Lists in which you can sort the elements. 我的建议是创建一个列表树 ,您可以在其中对元素进行排序。

If you are not interested about the ordering of the elements inside your list (and most people are usually not), you could also use a TreeMap (or HashMap) and use the homeTown as key and a List of all entries as value. 如果您对列表中元素的排序不感兴趣(大多数人通常不是这样),您也可以使用TreeMap(或HashMap)并使用homeTown作为键,并使用所有条目的List作为值。 If you add new elements, just look up the belonging list in the Map and append it (if it is the first element of course you need to create the list first). 如果添加新元素,只需在Map中查找属性列表并追加它(如果它是第一个元素,您需要先创建列表)。 If you want to delete an element simply do the same. 如果要删除元素,只需执行相同操作即可。

In the case you want a list of all users with a given homeTown you just need to look up that list in the Map and return it (no copying of elements needed), I am not 100% sure about the Map implementations in Java, but the complete method should be in constant time (worst case logarithmic, depending on the Map implementation). 如果你想要一个具有给定homeTown的所有用户的列表,你只需要在Map中查找该列表并返回它(不需要复制所需的元素),我不是100%肯定Java中的Map实现,但是完整的方法应该是恒定的时间(最坏的情况是对数,取决于Map的实现)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM