Java的Stream.flatMap()的(种类)逆操作是什么? [英] What is the (kind of) inverse operation to Java's Stream.flatMap()?
问题描述
Stream.flatMap()
操作转换
a, b, c
到包含每个输入元素的零个或多个元素的流中,例如
into a stream that contains zero or more elements for each input element, e.g.
a1, a2, c1, c2, c3
是否存在将一些元素分成一个新元素的相反操作?
Is there the opposite operations that batches up a few elements into one new one?
- 它不是.reduce(),因为它只产生一个结果
- 它不是collect(),因为它只填充容器(afaiu)
- 它不是forEach(),因为它只返回
void
并使用副作用
- It is not .reduce(), because this produces only one result
- It is not collect(), because this only fills a container (afaiu)
- It is not forEach(), because this has returns just
void
and works with side effects
它存在吗?我可以用任何方式模拟它吗?
Does it exist? can I simulate it in any way?
推荐答案
最后我发现 flatMap
是它自己的逆这么说。我监督 flatMap
不一定会增加元素的数量。它还可以通过为某些元素发出空流来减少元素的数量。要实现分组操作, flatMap
调用的函数需要最小的内部状态,即最新的元素。它要么返回一个空流,要么在组的末尾返回简化为组的代表。
Finally I figured out that flatMap
is its own "inverse" so to say. I oversaw that flatMap
not necessarily increases the number of elements. It may also decrease the number of elements by emitting an empty stream for some of the elements. To implement a group-by operation, the function called by flatMap
needs minimal internal state, namely the most recent element. It either returns an empty stream or, at the end of a group, it returns the reduced-to group representative.
这是一个快速实现 groupBorder
必须返回 true
如果传入的两个元素不属于同一组,即它们之间是组边界。 组合器
是组合函数,例如(1,a),(1,a),(1,a)组合成(3,a),给定你的组元素是,元组(int,string)。
Here is a quick implementation where groupBorder
must return true
if the two elements passed in do not belong to the same group, i.e. between them is the group border. The combiner
is the group function that combines, for example (1,a), (1,a), (1,a) into (3,a), given that your group elements are, tuples (int, string).
public class GroupBy<X> implements Function<X, Stream<X>>{
private final BiPredicate<X, X> groupBorder;
private final BinaryOperator<X> combiner;
private X latest = null;
public GroupBy(BiPredicate <X, X> groupBorder,
BinaryOperator<X> combiner) {
this.groupBorder = groupBorder;
this.combiner = combiner;
}
@Override
public Stream<X> apply(X elem) {
// TODO: add test on end marker as additonal parameter for constructor
if (elem==null) {
return latest==null ? Stream.empty() : Stream.of(latest);
}
if (latest==null) {
latest = elem;
return Stream.empty();
}
if (groupBorder.test(latest, elem)) {
Stream<X> result = Stream.of(latest);
latest = elem;
return result;
}
latest = combiner.apply(latest, elem);
return Stream.empty();
}
}
但有一点需要注意:运送最后一组在整个流中,必须将结束标记作为最后一个元素粘贴到流中。上面的代码假设它是 null
,但可以添加一个额外的结束标记测试器。
There is one caveat though: to ship the last group of the whole stream, an end marker must be stuck as the last element into the stream. The above code assumes it is null
, but an additional end-marker-tester could be added.
我无法想出一个不依赖于结束标记的解决方案。
I could not come up with a solution that does not rely on the end marker.
我还做了不会在传入和传出元素之间进行转换。对于一个独特的操作,这将是有效的。对于计数操作,上一步必须将各个元素映射到计数对象。
Further I did not also convert between incoming and outgoing elements. For a unique-operation, this would just work. For a count-operation, a previous step would have to map individual elements to a counting object.
这篇关于Java的Stream.flatMap()的(种类)逆操作是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!