英文:
Stream api reduce method
问题
以下是您要的翻译内容:
我正在学习流(Stream)API,并且在流的reduce方法上遇到了问题。我有一串字符串流,我想要将它们连接起来。以下是我的代码片段:
Stream<String> data = Stream.of("a", "b", "c", "d", "e", "f");
String col = data.parallel().reduce("dummy",
(t, u) -> {
return t + " : " + u;
},
(a, b) -> {
return a + b;
});
System.out.println(col);
//输出:dummy : adummy : bdummy : cdummy : ddummy : edummy : f
//期望:dummy : a : b : c : d : e : f
我不希望它们按顺序排列,但至少它们不应该有重复的“dummy”字符串。
这导致了奇怪的输出。请帮我找出问题所在。
英文:
I am learning Stream api and I am stuck at reduce method of Stream. I have stream of some string and I want to concate them. Below is my code snippet:
Stream<String> data = Stream.of("a", "b", "c", "d", "e", "f");
String col = data.parallel().reduce("dummy",
(t, u) -> {
return t + " : " + u;
},
(a, b) -> {
return a + b;
});
System.out.println(col);
//Output: dummy : adummy : bdummy : cdummy : ddummy : edummy : f
//Expected: dummy : a : b : c : d : e : f
I don't want them in sequence but at least they should not have repeated "dummy" String.
It results in a weird output. Please help me to find what's wrong here.
答案1
得分: 1
上面包含的reduce操作无法正常工作的原因是因为“标识值必须是组合函数的标识。这意味着对于所有u,combiner(identity, u)等于u。”
因为'dummy'不是字符串连接的有效标识,因为dummy + value不等于value。使用类似下面这样的替代方案应该可以工作:
public static void main(String args[])
{
Stream<String> data = Stream.of("a", "b", "c", "d", "e", "f");
System.out.println(data.parallel().reduce("", Test::accumulate));
}
private static String accumulate(String v1, String v2)
{
if(v1.isEmpty()) return v2;
if(v2.isEmpty()) return v1;
return v1 + ":" + v2;
}
作为替代方案,假设'dummy'只是因为reduce期望提供初始状态而包含在内,类似这样的方式可能适用于您的需求:
data.parallel().reduce((v1, v2) -> v1 + ":" + v2).orElse("???");
或者
data.parallel().collect(Collectors.joining(":"));
编辑 - 为什么reduce的行为是这样的?
在并发聚合数据时需要做出某些假设。例如,合并流中元素的顺序不应影响结果的有效性。为了解决这个问题,在约简操作中对可以使用的函数类型有一定的限制。其中一个限制是:
“标识值必须是组合函数的标识。这意味着对于所有u,combiner(identity, u)等于u。”
因此,至少可以说在并行执行时,标识可以传递给所有元素的功能上没有问题。关于为什么考虑以下可能会有帮助:
- 从计算的角度来看,如果只允许将第一个元素与标识组合,这意味着什么?
- 如果我也想立即开始处理第二个元素怎么办?
(更多细节请参见此答案:https://stackoverflow.com/a/51290673/14294525)
英文:
The reason the reduce included above doesn't work is because 'The identity value must be an identity for the combiner function. This means that for all u, combiner(identity, u) is equal to u.'
'dummy' is not a valid identity for String concatenation because dummy + value is not equal to value. Replacing with something like this should work:
public static void main(String args[])
{
Stream<String> data = Stream.of("a", "b", "c", "d", "e", "f");
System.out.println(data.parallel().reduce("", Test::accumulate));
}
private static String accumulate(String v1, String v2)
{
if(v1.isEmpty()) return v2;
if(v2.isEmpty()) return v1;
return v1 +":" + v2;
}
As an alternative, assuming 'dummy' is only included because reduce expects an initial state to be provided, something like this may work for your purposes:
data.parallel().reduce((v1, v2) -> v1 +":" + v2).orElse("???");
or
data.parallel().collect(Collectors.joining(":"));
Edit - Why is reduce behaving like this?
Certain assumptions need to be made when aggregating data concurrently. For example, the order in which elements in the stream are merged should not impact the validity of the result. To address this there are certain limitations on the types of functions which may be used in reduction operations. One limitation is:
'The identity value must be an identity for the combiner function. This means that for all u, combiner(identity, u) is equal to u.'
As such, at least we can say there is no reason functionally why the identity cannot be passed to all elements when executing in parallel. In terms of why considering the following may be useful:
- What does it mean from a computation perspective if only the first element allowed to be combined with the identity?
- What if I want to start processing the second element immediately also?
(See this answer for more detail: https://stackoverflow.com/a/51290673/14294525)
答案2
得分: 1
你还可以在不使用 reduce 的情况下使用以下代码:
Stream<String> data = Stream.of("a", "b", "c", "d", "e", "f");
String output = data.parallel().collect(Collectors.joining(" : ", "dummy : ", ""));
英文:
You can also use the below without reduce,
Stream<String> data = Stream.of("a", "b", "c", "d", "e", "f");
String output = data.parallel().collect(Collectors.joining(" : ", "dummy : ", ""));
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论