Эффективность кода в циклах Scala: считать вверх или вниз? - PullRequest
0 голосов
/ 20 октября 2018

Понятно, если вам нужно подсчитать, подсчитайте.Если вам нужно отсчитывать, считайте вниз.Однако, при прочих равных условиях, один быстрее другого?Вот мой Scala-код для хорошо известной головоломки - проверка, делится ли число на 13. В первом примере я переворачиваю свой массив и считаю в следующем цикле for в сторону увеличения.Во втором примере я оставляю массив один и выполняю уменьшающий цикл for.На первый взгляд второй пример выглядит быстрее.К сожалению, на сайте, где я запускаю код, время ожидания истекло.

 // works every time
object Thirteen {
import scala.annotation.tailrec

  @tailrec
  def thirt(n: Long): Long = {
    val getNum = (n: Int) => Array(1, 10, 9, 12, 3, 4)(n % 6)
    val ni  = n.toString.split("").reverse.map(_.toInt)
    var s: Long = 0
    for (i <- 0 to ni.length-1) {
        s += ni(i) * getNum(i)
    }
    if (s == n) s else thirt(s)
  }
}

// times out every time 
object Thirteen {
import scala.annotation.tailrec

  @tailrec
  def thirt(n: Long): Long = {
    val getNum = (n: Int) => Array(1, 10, 9, 12, 3, 4)(n % 6)
    val ni  = n.toString.split("").map(_.toInt)
    var s: Long = 0
    for (i <- ni.length-1 to 0 by -1) {
        s = s + ni(i) * getNum(i)
    }
    if (s == n) s else thirt(s)
  }
}

Я задаю следующие вопросы:

  1. Есть ли очевидное правило, о котором я не знаю?
  2. Какой простой способ проверить две версии кодадля производительности - надежное измерение производительности в JVM кажется трудным.
  3. Помогает ли это посмотреть на базовый байт-код?
  4. Есть ли лучший фрагмент кода, решающий ту же проблему, если это так, я был бы очень признателен за это.

Хотя я видел подобные вопросы, я могуне могу найти окончательный ответ.

1 Ответ

0 голосов
/ 20 октября 2018

Вот как я хотел бы заняться этим.

val nums :Stream[Int] = 1 #:: 10 #:: 9 #:: 12 #:: 3 #:: 4 #:: nums

def thirt(n :Long) :Long = {
  val s :Long = Stream.iterate(n)(_ / 10)
                      .takeWhile(_ > 0)
                      .zip(nums)
                      .foldLeft(0L){case (sum, (i, num)) => sum + i%10 * num}
  if (s == n) s else thirt(s)
}
...