在Scala中,我想编写以下C ++代码的等价物:
for(int i = 1 ; i * i < n ; i++)
到目前为止,我做到了这一点,但它看起来很难看,我认为它会一直持续到n:
for(i <- 1 to n
if(i * i < n))
有没有更好的方法来编写这段代码?
答案 0 :(得分:0)
不是更好但是方法不同
(1 to n).toStream map (i => i * i) takeWhile (_ < n)
scala> val res = (1 to 100).toStream map(i => i * i) takeWhile (_ < 100)
res: scala.collection.immutable.Stream[Int] = Stream(1, ?)
scala> res.toList
res16: List[Int] = List(1, 4, 9, 16, 25, 36, 49, 64, 81)
Stream
允许按需请求值,即延迟评估。因此,只有在请求下一个值时才会应用映射的函数。
答案 1 :(得分:0)
你拥有的解决方案可能不是最好的,但它可能是最有效的,其他一切在内部更复杂,所以它可能有一些开销。 (在大多数情况下,虽然不是一个值得注意的开销,但它可能会得到很好的优化。)
我不会在其他答案中使用Streams建议解决方案。虽然流是懒惰地计算的,但它们会缓存计算结果,在这种情况下不需要,如果迭代的范围很大,可能会占用大量内存。相反,我会使用迭代器。迭代器上的操作通常也是惰性的,不会缓存任何内容。
如果您经常需要这个,可以使用隐式类添加其他“运算符”,如下所示:
implicit class UntilHelper(start: Int) {
def aslong(cond: Int => Boolean) =
Iterator.from(start).takeWhile(cond)
}
你的循环看起来像这样:
for(i <- 1 aslong (Math.pow(_, 2) < 1000)) {
println(i)
}
从快速的微基准测试来看,它看起来比流解决方案快3倍,比简单的while循环慢一点。然而,如果没有任何背景,这些事情很难衡量。
计算一系列Squares的好方法是添加正方形之间的差异。这可以使用Stream或Iterator上的scanLeft方法完成。
val itr = Iterator.from(1).scanLeft(1)((a,b)=>a + 2*b+1)
println(itr.take(10).toList)
答案 2 :(得分:0)
首先,声明一个函数来生成一个懒惰的正方形流:
def squares(i: Int = 1): Stream[Int] = Stream.cons(i * i, squares(i + 1))
然后使用takeWhile在i * i小于n时获取值。例如:
scala> squares().takeWhile(_ < 50).foreach(println)
1
4
9
16
25
36
49