scala: сумма квадратов каждой четной цифры, начиная со 2-й позиции - PullRequest
0 голосов
/ 07 января 2020

Я могу использовать следующий код для суммирования квадратов каждой цифры. как это можно изменить, чтобы сделать это только для четных цифр, начиная со 2-й позиции?

var sum:Int = num.toString.map{ _.asDigit }.map(x => x*x).sum

Ответы [ 4 ]

2 голосов
/ 07 января 2020
  1. Если вам нужно каждое четно-позиционное значение, один из способов сделать это с помощью grouped и head.
  2. Чтобы начать со второго ди git, взять хвост список перед группировкой.
val sum = num.toString.map{ _.asDigit }.tail.grouped(2).map(_.head).map(x => x*x).sum

Посмотрите, как работает здесь .

1 голос
/ 07 января 2020

Одним из возможных решений, позволяющих сохранять только четное положение, является использование zipWithIndex:

// Your initial code
def squareDigitsSummation(n: Int): Int =
  n.toString.map{ _.asDigit }.map(x => x*x).sum

def squareEvenPositionedDigitsSummation(n: Int): Int =
  n.toString.view.
    tail.
    map(_.asDigit).
    zipWithIndex.
    collect { case (n, i) if i % 2 != 0 => n * n }.
    sum

assert(squareDigitsSummation(1234) == 30)
assert(squareEvenPositionedDigitsSummation(1234) == 9)

Обратите внимание, что zipWithIndex основано на 1, поэтому мне пришлось несколько нелогично отрицать filter предикат для хранения пар с нечетным индексом (я предполагал, что вы хотите иметь индексы на основе 0, если вы прямо упомянули, что не хотите, чтобы 0-й элемент сохранялся).

1 голос
/ 07 января 2020

сумма квадратов четных цифр из рекурсии правого хвоста

def sumOfEvenDigitsTailRecursion(num: Int): Int = {
  @tailrec def impl(num: Int, idx: Int, acc: Int): Int = {
    if (num == 0) acc
    else if (idx % 2 == 0) impl(num / 10, idx + 1, acc + ((num % 10) * (num % 10)))
    else impl(num / 10, idx + 1, acc)
  }
  impl(num, 1, 0)
}

assert(sumOfEvenDigitsTailRecursion(123456) == 5*5 + 3*3 +1*1)

сумма квадратов четных цифр из рекурсии левого хвоста

def sumOfEvenDigitsTailRecursion(num: Int): Int = {
  @tailrec def impl(num: Int, idx: Int, acc: Int, length: Int = -1): Int = {
    if (length % 2 == 0) {
      impl(num / 10, idx, acc + ((num % 10) * (num % 10)))
    } else {
      if (num == 0) acc
      else if (idx % 2 == 0) impl(num / 10, idx + 1, acc + ((num % 10) * (num % 10)))
      else impl(num / 10, idx + 1, acc)
    }
  }
  impl(num, 1, 0, (Math.log10(num) + 1).toInt)
}

assert(sumOfEvenDigitsTailRecursion(123456) == 2*2 + 4*4 + 6*6)

сумма квадратов четных цифры слева - итераторы

def sumOfEvenDigitsIterators(num: Int): Int =
  num
    .toString
    .iterator
    .map(_.asDigit)
    .grouped(2)
    .collect{ case ArraySeq(_, b) => b }
    .map(x => x * x)
    .sum

Тест: sbt "jmh:run -i 10 -wi 10 -f 2 -t 1 bench.So59627557"

@State(Scope.Benchmark)
@BenchmarkMode(Array(Mode.Throughput))
class So59627557 {
  def _sumOfEvenDigitsIterators(num: Int): Int =
    num
      .toString
      .iterator
      .map(_.asDigit)
      .grouped(2)
      .collect{ case ArraySeq(_, b) => b }
      .map(x => x * x)
      .sum

  def _sumOfEvenDigitsTailRecursion(num: Int): Int = {
    @tailrec def impl(num: Int, idx: Int, acc: Int, length: Int = -1): Int = {
      if (length % 2 == 0) {
        impl(num / 10, idx, acc + ((num % 10) * (num % 10)))
      } else {
        if (num == 0) acc
        else if (idx % 2 == 0) impl(num / 10, idx + 1, acc + ((num % 10) * (num % 10)))
        else impl(num / 10, idx + 1, acc)
      }
    }

    impl(num, 1, 0, (Math.log10(num) + 1).toInt)
  }

  val num: Int = (math.random * 100000000).toInt
  @Benchmark def sumOfEvenDigitsIterators: Int = _sumOfEvenDigitsIterators(num)
  @Benchmark def sumOfEvenDigitsTailRecursion: Int = _sumOfEvenDigitsTailRecursion(num)
}

результаты

[info] Benchmark                                 Mode  Cnt         Score        Error  Units
[info] So59627557.sumOfEvenDigitsIterators      thrpt   20   2033487.342 ± 187156.764  ops/s
[info] So59627557.sumOfEvenDigitsTailRecursion  thrpt   20  27431255.610 ± 835429.506  ops/s

Хвост-рекурсивное решение, кажется, имеет больше пропускная способность в 10 раз выше, чем у решений на основе итераторов.

0 голосов
/ 07 января 2020

Почему бы не использовать регулярные выражения?

val num = 24874
var sum: Int = "\\d{2}".r
  .findAllIn(num.toString)
  .map(_.last.asDigit)
  .map(v => v * v)
  .sum
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...