如何删除所有与特定条件匹配的元素,除了最大的元素与流API
我的问题是:有没有更好的方法来实施此任务?
我有一个有序元素的列表(在此示例中,age
,最小的第一个)。 我想删除满足条件的所有元素(在此示例 red elements 中),但请保留它们的第一个2
。
Stream<ElementsVO> stream = allElements.stream();
Stream<ElementsVO> redStream = stream.filter(elem->elem.getColor()==RED).sorted((c1, c2) -> { return c1.getAge() - c2.getAge();
}).limit(2);
Stream<ElementsVO> nonRedStream=stream.filter(elem->elem.getColor()!=RED);
List<ElementsVO> resultList = Stream.concat(redStream,nonRedStream).sorted((c1, c2) -> { return c1.getAge() - c2.getAge();
}).collect(Collectors.toList());
有什么想法可以改善这一点吗?有什么方法可以通过流实现累加器功能或类似的方法?
My question is: is there a better way to implement this task?
I have a list of orderable elements (in this example by age
, the youngest first).
And I want to delete all elements that fulfill a condition (in this example red elements) but keep the first 2
of them.
Stream<ElementsVO> stream = allElements.stream();
Stream<ElementsVO> redStream = stream.filter(elem->elem.getColor()==RED).sorted((c1, c2) -> { return c1.getAge() - c2.getAge();
}).limit(2);
Stream<ElementsVO> nonRedStream=stream.filter(elem->elem.getColor()!=RED);
List<ElementsVO> resultList = Stream.concat(redStream,nonRedStream).sorted((c1, c2) -> { return c1.getAge() - c2.getAge();
}).collect(Collectors.toList());
Any idea to improve this? Any way to implement an accumulator function or something like that with streams?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
从技术上讲,您可以使用一个陈述的谓词来完成此操作:
然后:
此可能会工作,但这是对流API的违反:
stream。 Filter
说谓词应该是无状态的,通常允许流实施以任何顺序应用过滤器。对于小输入列表,顺序流式流,这几乎可以肯定是列表中的外观顺序,但不能保证。警告。您当前的方式有效,尽管您可以使用
collectors.partitioningby
避免对其进行两次迭代。You can technically do this with a stateful predicate:
Then:
This might work, but it is a violation of the Stream API: the documentation for
Stream.filter
says that the predicate should be stateless, which in general allows the stream implementation to apply the filter in any order. For small input lists, streamed sequentially, this will almost certainly be the appearance order in the list, but it's not guaranteed.Caveat emptor. Your current way works, although you could do the partitioning of the list more efficiently using
Collectors.partitioningBy
to avoid iterating it twice.您可以实现自定义收集器,该将维护两个单独的RED 和 non-Red 元素的单独集合。
而且,由于您只需要两个红色元素即可提高性能,因此您可以引入部分分类。 IE的非红色元素的收集需要维护订单,并且最多必须是大小
2
,而与具有属性属性的元素的分类相比,排序的开销将远不那么重要。代码>红色仅选择其中两个。为了创建自定义收集器,您可以使用静态方法
collector.of()
,期望以下参数:2
键的地图(true
和false
),表示映射到此键的元素是 red 。为了存储 red elements 并执行部分分类,我们需要一个能够维护订单的集合。PriorityQueue
是为此目的的一个不错的选择。为了存储所有其他元素,我使用了arraydeque
,它不维护顺序,并且像arraylist
一样快。tryadd()
二进制处理器&lt; a&gt; a&gt; Combiner()
建立了一个规则,即如何合并并行执行流时获得的两个容器。在这里,组合仪依靠与累加器描述的相同逻辑。函数&lt; a,r&gt;
旨在通过转换可突变容器来产生最终结果。在下面的代码中,终结器将两个队列的内容都转储到流中,对它们进行分类并收集到不可变的列表中。collector.characteristics.unordered
。这表明并行产生的部分结果的部分结果的顺序不显着,可以通过平行流来改善该收集器的性能。该代码可能看起来像这样:
下面的方法负责创建基于给定谓词的元素的收集器,并将按照提供的比较器对它们进行排序。 。
此方法负责将下一个红元素添加到优先级队列中。它希望A 比较器为了确定是否应添加或丢弃下一个元素,以及队列的最大大小的值(
2
)检查是否超过。输出
You can implement a custom collector that will maintain two separate collections of RED and non-RED element.
And since you need only two red elements having the greatest age to improve performance, you can introduce a partial sorting. I.e. collection of non-red element needs to maintain an order and always must be of size
2
at most, with that overhead of sorting will be far less significant in comparison to sorting of elements having the property ofRED
in order to pick only two of them.In order to create a custom collector, you might make use of the static method
Collector.of()
which expects the following arguments:Supplier<A>
is meant to provide a mutable container which store elements of the stream. Because we need to separate elements by color into two groups as a container, we can use a map that will contain only2
keys (true
andfalse
), denoting whether elements mapped to this key are red. In order to store red-elements and perform a partial sorting, we need a collection that is capable of maintaining the order.PriorityQueue
is a good choice for that purpose. To store all other elements, I've usedArrayDeque
, which doesn't maintain the order and as fast asArrayList
.tryAdd()
BinaryOperator<A> combiner()
establishes a rule on how to merge two containers obtained while executing stream in parallel. Here, combiner rely on the same logic that was described for accumulator.Function<A,R>
is meant to produce the final result by transforming the mutable container. In the code below, finisher dumps the contents of both queues into a stream, sorts them and collects into an immutable list.Collector.Characteristics.UNORDERED
is being applied. Which indicates that the order in which partial results of the reduction produced in parallel is not significant, that can improve performance of this collector with parallel streams.The code might look like this:
The method below is responsible for creating of a collector that partition the elements based on the given predicate and will sort them in accordance with the provided comparator.
This method is responsible for adding the next red-element into the priority queue. It expects a comparator in order to be able to determine whether the next element should be added or discarded, and a value of the maximum size of the queue (
2
), to check if it was exceeded.Output
我写了一个带有谓词的通用收集器和一个要添加的元素的限制,与谓词相匹配:
用法:
I wrote a generic Collector with a predicate and a limit of elements to add which match the predicate:
Usage: