Java是否有Haskell scanr函数的对应实现?含标准库与Guava查询
好问题!Haskell的scanr确实是个很实用的工具,能输出fold过程中的所有中间结果。下面分别说说Java标准库和Guava里的情况:
Java标准库的实现情况
Java 8及以上的Stream API没有直接提供和Haskell scanr完全对应的原生函数——因为Stream是按左到右顺序处理的,原生不支持从右往左的扫描并输出所有中间结果。不过你可以通过三步模拟出scanr的效果:
- 先把输入集合反转
- 用循环或者自定义逻辑实现左扫描(类似Haskell的
scanl) - 最后把扫描结果反转回来
举个具体的例子,模拟Haskell里scanr (+) 0 [1,2,3]的效果:
import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; public class ScanrSimulation { public static void main(String[] args) { List<Integer> input = Arrays.asList(1, 2, 3); int initialValue = 0; // 第一步:反转输入列表 List<Integer> reversedInput = new ArrayList<>(input); Collections.reverse(reversedInput); // 第二步:左扫描累加 List<Integer> reversedResults = new ArrayList<>(); int accumulator = initialValue; reversedResults.add(accumulator); for (int num : reversedInput) { accumulator = num + accumulator; reversedResults.add(accumulator); } // 第三步:反转结果得到scanr的输出 Collections.reverse(reversedResults); System.out.println(reversedResults); // 输出 [6, 5, 3, 0] } }
Guava工具库的实现情况
Guava没有原生的scanr方法,但它提供的Streams.scan(左扫描)可以配合列表反转,更简洁地模拟scanr的行为:
- 用
Lists.reverse快速反转输入列表 - 调用
Streams.scan执行左扫描,传入累加器函数和初始值 - 再次反转结果列表,得到和
scanr一致的输出
示例代码如下:
import com.google.common.collect.Lists; import com.google.common.collect.Streams; import java.util.List; public class GuavaScanrSimulation { public static void main(String[] args) { List<Integer> input = Lists.newArrayList(1, 2, 3); int initialValue = 0; List<Integer> reversedInput = Lists.reverse(input); List<Integer> reversedResults = Streams.stream(reversedInput) .scan(initialValue, (accumulator, num) -> num + accumulator) .toList(); List<Integer> scanrResults = Lists.reverse(reversedResults); System.out.println(scanrResults); // 输出 [6, 5, 3, 0] } }
需要注意的是,Haskell的scanr是惰性求值的,但上面的模拟方式是严格求值的。如果你的场景需要惰性处理,可能需要自己实现一个从右往左遍历的迭代器来支持。
内容的提问来源于stack exchange,提问作者Vinothkumar Raman
相关产品推荐
相关产品推荐

