简体   繁体   English

使用 Java Streams,我可以根据与具有相同变量的辅助对象列表共享的变量过滤对象列表吗?

[英]With Java Streams, can I filter a list of objects based on a variable that is shared with a secondary list of objects with that same variable?

I am wondering if there is a way to simply the following code into a stream of some kind to work with, instead of having the for loop?我想知道是否有一种方法可以将以下代码简单地转换为某种流来使用,而不是使用 for 循环?

I am basically looking to filter out a certain group of Swimmers, while trying to also make sure that these swimmers are not already in the "AttendingList."我基本上是想过滤掉某一组游泳者,同时还要确保这些游泳者不在“参加名单”中。

List<Swimmer> swimmingList = //List generated from db;
List<SwimmerAttending> attendingList = //List generated from db;

for(SwimmerAttending s : attendinglist)
   {
     swimmingList = swimmingList.stream()
                                  .filter(i-> i.getSwimerNumber() > 1000 && !s.getSwimmerNumber().equals(i.getSwimmerNumber()))
                                  .collect(Collectors.toList());   
   }

So I am curious if there is a simpler way to do this with just using Streams?所以我很好奇是否有一种更简单的方法可以只使用 Streams 来做到这一点? Thanks you.谢谢。

Your code can be simplified and, more importantly, can be made to run in linear time, O(n), as opposed to quadratic time, O(n^2), currently, as you've a loop inside a loop (the stream iteration remains a loop, albeit a hidden one).您的代码可以简化,更重要的是,可以使代码在线性时间 O(n) 内运行,而不是二次时间 O(n^2),目前,因为您在循环内有一个循环(流迭代仍然是一个循环,尽管是一个隐藏的循环)。

To get linear time, you should convert your attending list to a set which can then be checked in constant time.要获得线性时间,您应该将您的出席列表转换为一组,然后可以在恒定时间内检查。 As such:像这样:

swimmingList = //List generated from db;
attendingList = //List generated from db;

Set<Integer> attendingSet = 
   attendingList.stream()
                .map(s -> s.getSwimmerNumber())
                .collect(Collectors.toCollection(HashSet::new));

swimmingList = swimmingList.stream()
                           .filter(i -> i.getSwimmerNumber() > 1000 
                                    && !attendingSet.contains(i.getSwimmerNumber()))
                           .collect(Collectors.toList());

The conversion to a set is linear (one loop) and the filter is also linear which makes a total linear algorithm.到集合的转换是线性的(一个循环)并且滤波器也是线性的,这构成了一个全线性算法。

If your swimming list has 1000 entries and your attending list has 1000 entries, your original code would iterate on each of the attending list entries, and for each attendee, iterate over the 1000 swimming list entry, making a total of 1,000,000 iterations.如果您的游泳列表有 1000 个条目,而您的参加列表有 1000 个条目,您的原始代码将迭代每个参加列表条目,并且对于每个参加者,迭代 1000 个游泳列表条目,总共进行 1,000,000 次迭代。 The new code will iterate over the attending list once (1000 iterations) and then iterate over the swimming list once (1000 iterations) with the membership check being done on a set which is constant time on a HashSet, making the total number of operations only 2000.新代码将遍历参加列表一次(1000 次迭代),然后遍历游泳列表一次(1000 次迭代),并在一个集合上进行成员资格检查,该集合是 HashSet 上的常量时间,从而使操作总数仅为2000。

You can map the attendinglist to their swimmer numbers first:您可以先将attendinglist名单映射到他们的游泳运动员号码:

List<Integer> attendingSwimmerNumbers = 
    attendingList.stream()
        .map(SwimmerAttending::getSwimmerNumber)
        .collect(Collectors.toList());

Then we can check if each swimmer's number is in the above list using contains :然后我们可以使用contains来检查每个游泳者的号码是否在上面的列表contains

 swimmingList = swimmingList.stream()
                              .filter(i-> i.getSwimmerNumber() > 1000 && attendingSwimmerNumbers.contains(i.getSwimerNumber()))
                              .collect(Collectors.toList());  

This is all assuming that swimmingList and attendingList store different types of objects.这一切都是假设swimmingListattendingList存储不同类型的对象。 If they store the same type, then it might make sense to override equals of SwimmerAttending to check equality of the swimmer number.如果它们存储相同的类型,那么覆盖SwimmerAttending equals以检查游泳者编号的相等性可能是有意义的。 Then you can use contains directly on the attendingList :然后您可以直接在attendingList上使用contains

 swimmingList = swimmingList.stream()
                              .filter(i-> i.getSwimmerNumber() > 1000 && attendingList.contains(i))
                              .collect(Collectors.toList()); 

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

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