带有 3 个参数的 Java.reduce 函数究竟是如何工作的?
Posted
技术标签:
【中文标题】带有 3 个参数的 Java.reduce 函数究竟是如何工作的?【英文标题】:How exactly does the Java.reduce function with 3 parameters work? 【发布时间】:2020-06-17 21:48:00 【问题描述】:我目前正在学习java.reduce()
,最近在阅读一些材料和浏览视频时遇到了一些事情。我知道有 3 种方法可以使用它,但是,我在使 3 参数之一工作时遇到问题。我希望有人能更好地解释它发生了什么,以及为什么我没有得到我例外的结果(一组 MagicNumber 对象的平均值)。这是我到目前为止的一个例子:
一个对象,我们称之为 MagicNumber.java
public class MagicNumber
Random randomValueGenerator = new Random();
int number;
public MagicNumber()
this.number = randomValueGenerator.nextInt();
包含幻数的随机流
public static Stream<MagicNumber> getNStream()
List<MagicNumber> magic = new ArrayList<MagicNumber>();
for(int i = 0; i < 100; i++)
magic.add(new MagicNumber());
return magic.stream();
返回平均幻数的函数
// This only returns the sum of the magic numbers and not the average
public static double average()
Stream<MagicNumbers> magicNumberStream = getNStream();
return magicNumberStream.reduce(
0.0, // initial value
(a,b) -> a + (double)b.number,
(a,b) -> (a + b)/100
)
正如评论所暗示的,上面只返回所有幻数的总和。虽然我期待一些东西。所以,我不相信我完全理解 reduce
函数中第三个参数的用途。此外,当我使用 2 个参数编写如下内容时:
返回平均幻数的函数
// This throws an error due to the return type
public static double average()
Stream<MagicNumbers> magicNumberStream = getNStream();
return magicNumberStream.reduce(
0.0, // initial value
(a,b) -> (double)(a.number + b.number)/100
)
我收到错误 Bad return type in lambda expression: double cannot be converted to MagicNumber
。有人可以解释(A)为什么这两个average
函数没有按预期工作,以及(B)如何修改它们以获得我正在寻找的结果?非常感谢您的帮助!
【问题讨论】:
你从哪里得到这个例子的? 我编的... 【参考方案1】:您误解了reduce()
的第三个参数。该参数是组合函数,它将两个中间结果组合成一个结果。
现在,您无法计算平均值的原因是,为了计算平均值,您必须将 Stream
减少为 2 个值 - 一个是元素的数量,另一个是它们的总和。一旦你得到这两个值,你就可以将它们分开。
为了让reduce()
产生两个值,您可以使用一些包含两个值的类,例如SimpleEntry
。
public static double average()
Stream<MagicNumber> magicNumberStream = getNStream();
Map.Entry<Integer,Double> sums =
magicNumberStream.reduce(
new SimpleEntry<Integer,Double>(0,0.0), // initial value (number of elements, sum)
(a,b) -> new SimpleEntry<>(a.getKey()+1,a.getValue()+b.number),
(a,b) -> new SimpleEntry<>(a.getKey()+b.getKey(),a.getValue()+b.getValue()));
return sums.getValue()/sums.getKey();
【讨论】:
Eran,我注意到在我的回答中,即使我删除了 parallel(),我仍然得到正确的平均值。你能告诉我为什么会这样吗?如果您愿意,我可以将其作为单独的问题发布。谢谢。这里 - ***.com/a/60554907/6648326 @MasterJoe2 如果您遵循 Stream 方法的约定,则流应该产生相同的输出,无论它是并行的还是顺序的。因此,删除parallel()
应该没有什么不同。
Eran,我问了一个相关的问题。随时回答 - ***.com/questions/60555563/… 谢谢。【参考方案2】:
免责声明 - 我是 lambdas 和一般流的初学者。
我认为Eran's answer 更好。但是,我也会添加我的答案。如果需要,这里是与此问题相关的 Streams 上的 short tutorial。
我使用了一个选定整数的列表,而不是你的“幻数”。这是相同的,因为幻数在您的示例中只是整数。所以我们实际上只是在计算整数的平均值。此外,使用我们可以决定其数量的列表将很容易测试和学习。找出 lambda 部分后,您可以将 List<Integer>
替换为 List<MagicNumber>
并相应地更新代码。
虽然不需要,但我将使用并行流来回答您的问题。代码的解释在cmets中。
import java.util.Arrays;
import java.util.List;
public class Temp
public static void main(String [] args)
//For example, consider a list of a *series* of numbers in increasing order.
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
int n = numbers.get(numbers.size()-1);//n = 6 is the number of numbers in list.
double expectedSum = (n * (n + 1))/2;//By mathematical formula for increasing series.
Double sum = numbers
//Take a stream of numbers - it could be integers, "magic numbers" or any other number.
.stream()
//Split the stream into mini streams and calculate sum of each of mini stream.
.parallel()
//Reduce all the numbers in a stream to their sum.
.reduce(
//start with a partial sum of 0.
0.0,
//For a stream, calculate the sum of all the numbers.
(partialSum, nextNumber) -> partialSum + (double) nextNumber,
//Add the sums of each mini stream.
(onePartialSum, anotherPartialSum) -> (onePartialSum + anotherPartialSum)
);
System.out.println("Sum : expected value = " + expectedSum + ", actual value = " + sum);
double expectedAverage = expectedSum/numbers.size();
double average = sum/numbers.size();
System.out.println("Average : expected value = " + expectedAverage + ", actual value = " + average);
输出:
Sum : expected value = 21.0, actual value = 21.0
Average : expected value = 3.5, actual value = 3.5
【讨论】:
实际上,我认为您的问题本身也可以回答我的问题。我对 reduce 方法中的最后一个参数感到困惑。【参考方案3】:以下是我想基于以下问题讨论的一些要点:具有 3 个参数的 reduce 方法如何工作? 1.如果我们不使用并行流方法,那么简单地减少方法使用标识和累加器, 下面是同样的演示,
int length=se.reduce(0,//identity
//below is the Accumulator that is Bifunctional parameter
(i,s)->
System.out.println("Initial Value= "+i+" with Stream Object="+s+" Addition is ="+(i+s.length()));//extra work to understand the data
return i+s.length();,
//below is the BinaryOperator method which never gets executed in single pipe Stream**strong text**,
(a,b)->
System.out.println("First Value that passed to combiner = "+a+" Second value ="+b);//never gets called in single stream
return a+b;);
System.out.println(length);
输出
Initial Value= 0 with Stream Object=I Addition would be =1
Initial Value= 1 with Stream Object=am Addition would be =3
Initial Value= 3 with Stream Object=The Addition would be =6
Initial Value= 6 with Stream Object=King Addition would be =10
Initial Value= 10 with Stream Object=Of Addition would be =12
Initial Value= 12 with Stream Object=Java Addition would be =16
16
在我们应用并行流的第二种情况下,Combiner 将被执行,
public static int z=0;//need to put outside of public static void main(String[] args);
List<String> ll=List.of("I","am","very","Brave");
ll.parallelStream().reduce(0,(i,s)->
System.out.println("Initial Value= "+i+" with Stream Object="+s+" With Stream Number= "+z++);
return i+s.length();,(a,b)->
System.out.println("First Value that passed to combiner = "+a+" Second value ="+b);
return a+b;);
System.out.println(Length);
运行后,我们得到以下输出,
Initial Value= 0 with Stream Object=very With Stream Number= 0
Initial Value= 0 with Stream Object=am With Stream Number= 1
Initial Value= 0 with Stream Object=I With Stream Number= 2
Initial Value= 0 with Stream Object=Brave With Stream Number= 3
First Value that passed to combiner = 1 Second value =2
First Value that passed to combiner = 4 Second value =5
First Value that passed to combiner = 3 Second value =9
12
这清楚地表明身份每次只是传递0值,因此每个流都不同,需要组合器来组合结果, 谢谢!
【讨论】:
在提供答案时避免使用诸如“我想根据问题讨论的一些观点”之类的短语。讨论不应成为答案的一部分;改用 cmets ot chat。以上是关于带有 3 个参数的 Java.reduce 函数究竟是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章
opencv库中houghcircle函数中的dp参数究竟是如何工作的?
HttpGetAttribute不包含带有1个参数的构造函数