質問

I am trying to implement ugly number sequence generation in 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...

I have implemented using var keyword like java implementation and it is working fine. Here is the ideone link of complete code: http://ideone.com/qxMEBw

Can someone suggest better of implementing it using Scala idioms and without using mutable values.

Pasting code here for reference :

/**
 * 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
  }
}
役に立ちましたか?

解決

could take a look at following codes, using stream & recursion:

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)
}

The output for the first 30 ugly numbers:

  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)

revise it to use your way

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)

他のヒント

So, how about this one:

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)
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top