Удалить изменяемую сумму var

Вот расчет энтропии, основанный на ответе Джеффа Этвуда: Как рассчитать энтропию файла? который основан на http://en.wikipedia.org/wiki/Entropy_(information_theory):

object MeasureEntropy extends App {

  val s = "measure measure here measure measure measure"

  def entropyValue(s: String) = {

    val m = s.split(" ").toList.groupBy((word: String) => word).mapValues(_.length.toDouble)
    var result: Double = 0.0;
    val len = s.split(" ").length;

    m map {
      case (key, value: Double) =>
        {
          var frequency: Double = value / len;
          result -= frequency * (scala.math.log(frequency) / scala.math.log(2));
        }
    }

    result;
  }

  println(entropyValue(s))
}

Я хотел бы улучшить это, удалив изменяемое состояние, относящееся к:

var result: Double = 0.0;

Как совместить result в единый расчет над map функция?

3 ответа

Решение

С помощью foldLeftили в этом случае /: который является синтаксическим сахаром для него:

(0d /: m) {case (result, (key,value)) => 
  val frequency = value / len
  result - frequency * (scala.math.log(frequency) / scala.math.log(2))
}

Документы: http://www.scala-lang.org/files/archive/api/current/index.html:B(op:(B,A)=>B): В

Просто sum сделает свое дело:

m.map {
  case (key, value: Double) =>
     val frequency: Double = value / len;
      - frequency * (scala.math.log(frequency) / scala.math.log(2));
}.sum

Это может быть написано с использованием foldLeft, как показано ниже.

  def entropyValue(s: String) = {
    val m = s.split(" ").toList.groupBy((word: String) => word).mapValues(_.length.toDouble)
    val len = s.split(" ").length
    m.foldLeft(0.0)((r, t) => r - ((t._2 / len) * (scala.math.log(t._2 / len) / scala.math.log(2))))
  }
Другие вопросы по тегам