在scala中实现丑陋的数字

时间:2014-03-24 04:39:46

标签: scala scala-collections

我正在尝试在Scala中实现丑陋的数字序列生成。  丑陋的数字是唯一的素因子为2,3或5的数字。序列1,2,3,4,5,6,8,9,10,12,15 ......

我已经实现了使用var关键字,如java实现,它工作正常。以下是完整代码的ideone linkhttp://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
  }
}

2 个答案:

答案 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)