scala 输入流_Scala流的记忆化

本文探讨了Scala中流(Streams)的记忆化(memoization)问题,特别是在解决欧拉问题5时遇到的OutOfMemoryError错误。通过修改流生成器函数并使用迭代器的find方法,解决了由流记忆导致的问题。同时,对比了Java8流的解决方案。

scala 输入流

我了解了scala在内部使用Streams记忆的困难方式。

这是我第一次尝试解决欧拉问题5

def from(n: Int): Stream[Int] = n #:: from(n + 1)

def isDivisibleByRange(n: Int, r: Range) = {
  r.forall(n % _ == 0)
}

val a = from(21)
val o = a.find(isDivisibleByRange(_, Range(2, 21)))
o match {
  case Some(i) => println(i)
  case None => println("Nothing found!")
}

我对这个代码为什么会抛出OutOfMemoryError感到有些迷惑,这要归功于Stackoverflow ,因为对这个问题的答案是非常高的232792560,该范围内的所有整数都会在流的不同节点内存储,因此这个问题。

这实际上很容易看到,让我首先修改流生成器函数的副作用:

def from(n: Int): Stream[Int] = {println(s"Gen $n"); n #:: from(n + 1)}
val s = from(1)
s.take(10).toList 
s.take(10).toList

第二条语句不会打印任何内容。

鉴于这种记忆行为,有一些可能的修复方法,最简单的方法是在任何地方都不保留对流头的引用,而使用迭代器的find方法:

from(1).iterator.find(isDivisibleByRange(_, Range(1, 21)))

值得一提的是,Java 8流并没有被记住,而使用Java 8流的解决方案(可以大幅度地改进)如下:

@Test
public void testStreamOfInts() {
 Stream<Integer> intStream = Stream.generate(from(1));
 List<Integer> upto20 = IntStream.rangeClosed(1, 20).boxed().collect(Collectors.toList());
 Predicate<Integer> p = (i -> isDivisibleOverRange(i, upto20));
 Optional<Integer> o = intStream.filter(p).findFirst();
 o.ifPresent(i -> System.out.println("Found: " + i));
}

private Supplier<Integer> from(Integer i) {
 AtomicInteger counter = new AtomicInteger(0);
 return () ->  counter.incrementAndGet();
}

private boolean isDivisibleOverRange(Integer n, List<Integer> l) {
 return l.stream().allMatch(i -> n % i == 0);
}

翻译自: https://www.javacodegeeks.com/2014/04/memoization-of-scala-streams.html

scala 输入流

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值