我尝试了解java-8中的reduce()
方法是如何工作的。
例如,我有以下代码:
public class App {
public static void main(String[] args) {
String[] arr = {"lorem", "ipsum", "sit", "amet"};
List<String> strs = Arrays.asList(arr);
int ijk = strs.stream().reduce(0,
(a, b) -> {
System.out.println("Accumulator, a = " + a + ", b = " + b);
return a + b.length();
},
(a, b) -> {
System.out.println("Combiner");
return a * b;
});
System.out.println(ijk);
}
}
输出为:
Accumulator, a = 0, b = lorem
Accumulator, a = 5, b = ipsum
Accumulator, a = 10, b = sit
Accumulator, a = 13, b = amet
17
是这些字符串长度的总和。而且我看到未访问组合器,因此它不会与数字相乘,只会将数字相加。
但是,如果我有这些信息流:
int ijk = strs.parallelStream().reduce(0,
(a, b) -> {
System.out.println("Accumulator, a = " + a + ", b = " + b);
return a + b.length();
},
(a, b) -> {
System.out.println("Combiner");
return a * b;
});
System.out.println(ijk);
这是输出:
Accumulator, a = 0, b = ipsum
Accumulator, a = 0, b = lorem
Accumulator, a = 0, b = sit
Combiner
Accumulator, a = 0, b = amet
Combiner
Combiner
300
我看到累加器和合并器都被访问了,但是只返回了乘法。那么总和会怎样?
答案 0 :(得分:16)
您应该阅读reduce
的说明文件:
此外,组合器功能必须与累加器功能兼容;对于所有u和t,必须满足以下条件:
combiner.apply(u,accumulator.apply(identity,t))== accumulator.apply(u,t)
在您的情况下,您正在违反该定律(在accumulator
中执行 sum ,在combiner
中进行乘法),因此结果您会发现这种操作实际上是未定义的,并且取决于基础源的Spliterator的实现方式(不要这样做!)。
此外,combiner
仅被 称为并行流。
当然,您的整个方法可以简化为:
Arrays.asList("lorem", "ipsum", "sit", "amet")
.stream()
.mapToInt(String::length)
.sum();
如果您只是出于学习目的而这样做,那么正确的reduce
将是(获取sum
):
strs.parallelStream()
.reduce(0,
(a, b) -> {
System.out.println("Accumulator, a = " + a + ", b = " + b);
return a + b.length();
},
(a, b) -> {
System.out.println("Combiner");
return a + b;
});
答案 1 :(得分:8)
关键概念:身份,累加器和组合器
Stream.reduce()操作:将操作的参与者元素分解为单独的块。这样,我们将更容易理解每个人扮演的角色
当流并行执行时,Java运行时将流拆分为多个子流。在这种情况下,我们需要使用一种函数将子流的结果合并为一个。这就是组合器的作用
案例1:如您的示例所示,合并器可与parallelStream
一起使用
案例2:具有不同类型参数的示例累加器
在这种情况下,我们有一个User对象流,累加器参数的类型为Integer和User。但是,累加器实现是整数的总和,因此编译器无法推断用户参数的类型。
List<User> users = Arrays.asList(new User("John", 30), new User("Julie", 35));
int computedAges = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge());
编译错误
The method reduce(User, BinaryOperator<User>) in the type Stream<User> is not applicable for the arguments (int, (<no type> partialAgeResult, <no type> user) -> {})
我们可以使用Combiner(方法引用Integer::sum
或lambda表达式(a,b)->a+b
int computedAges = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(),Integer::sum);
简单地说,如果我们使用顺序流,并且累加器参数的类型及其实现的类型匹配,则无需使用组合器。
答案 2 :(得分:8)
有3种减少使用java-stream的方法。简而言之,for it in tablewidget.selectedItems():
print(it.row(), it.column())
以两个后续项(或与第一项相同的标识值)开始,并执行操作以使它们产生新的折减值。对于每个下一项,都会发生相同的情况,并以减小的值执行操作。
假设您有from PyQt5 import QtCore, QtGui, QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.table = QtWidgets.QTableWidget(6, 6)
self.setCentralWidget(self.table)
self.table.selectionModel().selectionChanged.connect(
self.on_selectionChanged
)
@QtCore.pyqtSlot(QtCore.QItemSelection, QtCore.QItemSelection)
def on_selectionChanged(self, selected, deselected):
print("=====Selected=====")
for ix in selected.indexes():
print(ix.row(), ix.column())
print("=====Deselected=====")
for ix in deselected.indexes():
print(ix.row(), ix.column())
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
,Stream::reduce
,'a'
和'b'
的信息流。减少执行以下操作序列:
'c'
-'d'
可以是任何东西(输入长度的总和。)result = operationOn('a', 'b')
operationOn
result = operationOn(result, 'c')
方法是:
Optional<T> reduce(BinaryOperator<T> accumulator)
对元素进行归约。从头两个项目产生一个减少的值开始,然后每个项目都有一个减少的值。返回result = operationOn(result, 'd')
,因为它不能保证输入流不为空。
T reduce(T identity, BinaryOperator<T> accumulator)
的作用与上述方法相同,只是将身份值作为第一项给出。由于result is returned
的缘故,至少保证了一项,所以返回Optional<T>
。
U reduce(U identity, BiFunction<U,? super T, U> accumulator, BinaryOperator<U> combiner)
的功能与上述方法相同,此外还合并了功能。由于T
的缘故,至少保证了一项,所以返回T identity
。
答案 3 :(得分:1)
我假设您选择像演示一样进行加法和乘法以查看实际发生的情况。
正如您已经注意到的那样,正如已经提到的,仅在并行流上调用组合器。
简而言之,在并行strams上,一部分流(分别是基础的分隔符)被截断并由其他线程处理。处理了几个部分后,将它们的结果与组合器合并。在您的情况下,所有四个元素都由不同的线程处理,然后按元素进行组合。这就是为什么您看不到任何加法(除0 +
之外)而只应用乘法的原因。
但是,为了获得有意义的结果,您应该从*
切换到+
,而进行更有意义的输出。