过滤流对另一个列表中的项目

时间:2017-01-29 14:13:50

标签: java for-loop java-8 java-stream

针对不同列表中的数据尝试filter流:

它可以工作,但我在流的中间使用了一个for循环。我找不到有关如何将for循环转换为流的任何信息。

我可以.stream() selction.getItems()而不是.forEach()并且有一个新的.stream() DATA.accounts,但这是糟糕的代码,因为它必须在每个.forEach.

        y=1;

        DATA.accounts.stream()
            .flatMap(estimate -> estimate.getElements().stream())
            .filter( ele-> {

                // different list;
                for (Element element:selection.getItems()){
                    if (element.getId()==ele.getId()){
                        return true;
                    }
                }
                return false;
            })

            .forEach(element -> {
                element.setDateSchedualed(selectedDate);
                element.setOrder(y);    
                y++;
            });

4 个答案:

答案 0 :(得分:1)

我认为你真正需要的是:

list1.removeAll(list2);

虽然没有涉及流。

答案 1 :(得分:1)

将其他列表的ID放在Set selectedIds中,然后根据ele-> selectedIds.contains(ele.getId())进行过滤。

这将给你(摊销)线性时间复杂度。

由于你需要在selected中检查流中每个项目的所有元素之间的存在,我不希望有任何简单的方法只使用流(因为你无法真正流式传输{{1}这个任务的集合。)

答案 2 :(得分:1)

您可以将filter表达为

.filter(ele -> selection.getItems().stream()
                        .anyMatch(element -> element.getId()==ele.getId())

这个“必须重新预定”的事实不应该比原始代码为每个元素循环的事实更加困扰。在任何一种情况下,您都创建了O(n×m)时间复杂度的操作。如果您可以肯定地预测其中一个列表总是非常小,那么这是可以接受的。

否则,通过将id值存储在具有快速(在最佳情况下为O(1))查找的结构中,无法准备此操作。即。

Set<IdType> id = selection.getItems().stream()
    .map(element -> element.getId())
    .collect(Collectors.toSet());

…

.filter(ele -> id.contains(ele.getId())

除此之外,当forEach是局部变量时,y方法明确增加y变量是一种反模式,甚至不编译。如果y是一个字段,它会使这个代码更糟糕。在这里,接受临时存储到List

更加清晰
Set<IdType> id = selection.getItems().stream().map(element -> element.getId());

List<ElementType> list = DATA.accounts.stream()
    .flatMap(estimate -> estimate.getElements().stream())
    .filter(ele -> id.contains(ele.getId())
    .collect(Collectors.toList());

IntStream.range(0, list.size())
    .forEach(ix -> {
        ElementType element = list.get(ix);
        element.setDateSchedualed(selectedDate);
        element.setOrder(ix+1);
    });

答案 3 :(得分:0)

我认为如果你想在线性时间内搜索id,那么使用for-each循环实际上并没有什么问题,因为例如你的项目列表是ArrayList并且你使用了{{1}过滤的方法,它实际上也只是循环元素。您可以编写一般包含函数,如:

contains

并用它替换你的for-each循环:

public static <E1, E2> boolean contains(Collection<E1> collection, E2 e2, BiPredicate<E1, E2> predicate){
    for (E1 e1 : collection){
        if (predicate.test(e1, e2)){
            return true;
        }
    }
    return false;
}