直到平方根

时间:2016-01-29 10:51:18

标签: scala

在Scala中,我想编写以下C ++代码的等价物:

for(int i = 1 ; i * i < n ; i++)

到目前为止,我做到了这一点,但它看起来很难看,我认为它会一直持续到n:

for(i <- 1 to n 
            if(i * i < n))

有没有更好的方法来编写这段代码?

3 个答案:

答案 0 :(得分:0)

不是更好但是方法不同

使用流

(1 to n).toStream map (i => i * i) takeWhile (_ < n)

n = 100

的示例
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