我正在尝试在Scala中实现丑陋的数字序列生成。 丑陋的数字是唯一的素因子为2,3或5的数字。序列1,2,3,4,5,6,8,9,10,12,15 ......
我已经实现了使用var关键字,如java实现,它工作正常。以下是完整代码的ideone link:http://ideone.com/qxMEBw
有人建议使用Scala惯用法更好地实现它,而不使用可变值。
在此处粘贴代码以供参考:
/**
* Ugly numbers are numbers whose only prime factors are 2, 3 or 5. The sequence
* 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15,
* shows the first 11 ugly numbers. By convention, 1 is included.
* Write a program to find and print the 150th ugly number.
*
*/
object UglyNumbers extends App {
var uglyNumbers = List(1)
val n = 11
var i2 = 0;
var i3 = 0;
var i5 = 0;
// initialize three choices for the next ugly numbers
var next_multiple_2 = uglyNumbers(i2) * 2;
var next_multiple_3 = uglyNumbers(i3) * 3;
var next_multiple_5 = uglyNumbers(i5) * 5;
for (i <- 0 to n) {
val nextUglyNumber = min(next_multiple_2, next_multiple_3, next_multiple_5)
uglyNumbers = uglyNumbers :+ nextUglyNumber
if (nextUglyNumber == next_multiple_2) {
i2 = i2 + 1
next_multiple_2 = uglyNumbers(i2) * 2
}
if (nextUglyNumber == next_multiple_3) {
i3 = i3 + 1
next_multiple_3 = uglyNumbers(i3) * 3
}
if (nextUglyNumber == next_multiple_5) {
i5 = i5 + 1
next_multiple_5 = uglyNumbers(i5) * 5
}
}
for (uglyNumber <- uglyNumbers)
print(uglyNumber + " ")
def min(a: Int, b: Int, c: Int): Int = (a, b, c) match {
case _ if (a <= b && a <= c) => a
case _ if (b <= a && b <= c) => b
case _ => c
}
}
答案 0 :(得分:5)
可以看一下下面的代码,使用stream&amp;递归:
object App extends App {
val ys = Array(2, 3, 5)
def uglynumber(n: Int): Boolean =
n match {
case x if x == 1 => true
case x if x % 5 == 0 => uglynumber(x / 5)
case x if x % 3 == 0 => uglynumber(x / 3)
case x if x % 2 == 0 => uglynumber(x / 2)
case _ => false
}
def uglynumbers: Stream[Int] = {
def go(x: Int): Stream[Int] =
if (uglynumber(x)) x #:: go(x + 1)
else go(x + 1)
go(1)
}
println(uglynumbers.take(30).toList.sorted)
}
前30个丑陋数字的输出:
List(1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32, 36, 40, 45, 48, 50, 54, 60, 64, 72, 75, 80)
修改它以使用你的方式
def nums: Stream[Int] = {
def go(a: Int, b: Int, c: Int): Stream[Int] = {
val xs = nums.take(a.max(b.max(c))).toArray
val a2 = 2 * xs(a - 1)
val b3 = 3 * xs(b - 1)
val c5 = 5 * xs(c - 1)
if (a2 <= b3 && a2 <= c5) a2 #:: go(a + 1, b, c)
else if (b3 <= a2 && b3 <= c5) b3 #:: go(a, b + 1, c)
else c5 #:: go(a, b, c + 1)
}
(1 #:: go(1, 1, 1)).distinct
}
println(nums.take(30).toList)
答案 1 :(得分:1)
那么,这个怎么样:
scala> lazy val ugly: Stream[Int] = 1 #:: Stream.from(2).filter{ n =>
| ugly.takeWhile(n/2>=).flatten(x => Seq(2, 3, 5).map(x*)).contains(n)
| }
warning: there were 2 feature warning(s); re-run with -feature for details
ugly: Stream[Int] = <lazy>
scala> ugly.take(30).toList
res5: List[Int] = List(1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18,
20, 24, 25, 27, 30, 32, 36, 40, 45, 48, 50, 54, 60, 64, 72, 75, 80)