scala как использовать val вместо var - PullRequest
0 голосов
/ 15 декабря 2018

Я очень новичок в Scala, и я написал некоторый код, используя var.Я слышал, что использование var не рекомендуется в Scala, поэтому я хочу попробовать использовать только val.Я исследовал и пробовал разные способы, но не смог получить тот же результат, что и при использовании var.

def yearly_yield(data: List[List[Option[Double]]], balance: Long, index: Int): Long = {
  val year = data(index)
  var size = 0
  var invYield = 0.0

  for( j <- year)
    if(j.isDefined)
      size = size + 1

  val amount = balance/size

  for( i <- year.indices)
    if (year(i).isDefined)
      invYield += amount * year(i).get

  balance + invYield.toLong
}

, а другой -

def compound_yield(data: List[List[Option[Double]]], balance: Long, index: Int): Long = {
  var newBalance = balance
  for( i <- 0 until index) 
    newBalance = yearly_yield(data, newBalance, i)

  newBalance
}

Я думаю, что могу попробовать использовать рекурсию для compound_yield, но я постоянно получаю ошибки ..

Ответы [ 3 ]

0 голосов
/ 15 декабря 2018

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

def yearly_yield(data: List[Option[Double]], balance: Long): Long =
{
  val year = data.flatten //Remove all the None's
  (year.fold(0.0)(_+_)*balance/year.size).toLong
}

Тогда ваша сложная операция доходности просто складывает годовой доход слева направо.

def compound_yield(data: List[List[Option[Double]]], balance): Long = 
  data.foldLeft(0l)((balance, year) => balance * yearly_yield(year))
0 голосов
/ 15 декабря 2018

Итак, годовой год - это просто:

def yearly(data: List[Option[Double]], balance: Long): Double = {
  val interest = year.flatten
  interest.map(_ * balance).sum / interest.size
}

Вам не нужно отправлять все годы, а индекс только для того, чтобы посмотреть на него (а произвольный доступ для List - это не то, что выдолжен сделать так или иначе), поэтому я настроил параметры соответственно.Он также должен возвращать Double вместо Long.

.flatten здесь превращает List[Option[Double]] в List[Double], выбрасывая те опции, которые None, и распаковывая остальные в Double..map пересекает список и вызывает функцию для каждого элемента (_ является сокращением для аргумента, который является текущим элементом списка).Затем мы складываем все вместе .sum и делим на размер (эта последняя часть кажется неправильной, я не знаю, почему вы хотите сделать это, кстати).

Обратите внимание, что .flatten, .map, .sum и .size каждый пересекает один и тот же список, который может считаться расточительным.Если year - это список месяцев, а их около 12, это не имеет большого значения, и я призываю вас сделать это таким образом для выразительности.Но если мы говорим о миллиардах элементов, возможно, извлеченных из удаленного хранилища, это может стать недопустимым.Для этого случая всегда есть .foldLeft:

 val (total, size) = data.foldLeft((0, 0)) { 
   case ((total, size), Some(elem)) => (total + elem*balance, size + 1)
   case (passThrough, _) => passThrough
 }
 total/size

Это то же самое, что и в первой версии, но только с одним проходом по списку..foldLeft пересекает список, как .map, но вместо того, чтобы просто передать текущий элемент списка в вашу функцию, он передает то, что возвратил в прошлый раз (или начальное значение, вы задаете его в качестве параметра для первого вызова), и текущий элемент, и, в конце концов, вы получите результат последнего выполнения функции, а не весь список.

Теперь, к составлению.Вы хотите начать с баланса и проходить каждый год, применяя трансформацию..foldLeft делает именно это:

 data.foldLeft(balance) { case (balance, year) => balance + yearly(year, balance) }
0 голосов
/ 15 декабря 2018

Как то так?

def yearly_yield(data    :List[List[Option[Double]]]
                ,balance :Long, index: Int) :Long = {
  val year   :List[Double] = data(index).flatten
  val amount :Long         = balance/year.length

  year.foldLeft(0.0){case (acc, d) => acc + amount * d}.toLong

}

def compound_yield(data    :List[List[Option[Double]]]
                  ,balance :Long, index: Int) :Long =
  (0 until index).foldLeft(balance){ case (nb, idx) =>
    yearly_yield(data, nb, idx)
  }
...