Scala: почему mapValues создает представление и есть ли стабильные альтернативы?



только сейчас я с удивлением узнал, что mapValues производит вид. Следствие показано в следующем примере:



case class thing(id: Int)
val rand = new java.util.Random
val distribution = Map(thing(0) -> 0.5, thing(1) -> 0.5)
val perturbed = distribution mapValues { _ + 0.1 * rand.nextGaussian }
val sumProbs = perturbed.map{_._2}.sum
val newDistribution = perturbed mapValues { _ / sumProbs }


идея заключается в том, что у меня есть дистрибутив, который возмущается с какой-то случайности, то я перенормировывать его. Код фактически терпит неудачу в своем первоначальном намерении: так как mapValues производит view,_ + 0.1 * rand.nextGaussian всегда переоценивается всякий раз, когда есть.



Я сейчас делаю что-то вроде distribution map { case (s, p) => (s, p + 0.1 * rand.nextGaussian) }, но это всего лишь немного многословный. Итак, цель этого вопроса:




  1. напомните людям, которые не знают об этом факте.

  2. искать причины, почему они делают mapValues выход view s.

  3. есть ли альтернативный метод, который производит бетон Map.

  4. существуют ли другие широко используемые методы сбора, которые имеют эту ловушку.


спасибо.

633   2  

2 ответов:

есть билет об этом,SI-4776 (по YT).

фиксация, которая вводит его, должна сказать следующее:

следуя предложению джрудольфа, сделал filterKeys и mapValues преобразование абстрактных карт и дублированная функциональность для неизменяемых карты. Переехал transform и filterNot от неизменяемых к общим картам. Обзор от phaller.

Я не смог найти оригинальное предложение джрудольфа, но я предполагаю это было сделано, чтобы сделать mapValues более эффективным. Дайте вопрос, который может стать сюрпризом, но mapValuesи более эффективно, если вы вряд ли будете повторять значения более одного раза.

в качестве обхода можно сделать mapValues(...).view.force чтобы создать новый Map.

доктор Скала говорит:

вид карты, который карты каждый key от этой карты до f(this(key)). Полученная карта обертывает исходную карту без копирования каких-либо элементов.

так что этого следует ожидать, но это меня очень пугает, мне придется пересмотреть кучу кода завтра. Я не ожидал такого поведения: - (

просто другой обходной путь:

можно назвать toSeq чтобы получить копию, и если вам это нужно обратно на карту toMap, но это ненужное создание объектов и имеет значение производительности при использовании map

можно относительно легко писать, a mapValues который не создает представление, я сделаю это завтра и опубликую код здесь, если никто не сделает это до меня;)

EDIT:

Я нашел простой способ "заставить" вид, использовать ".map (identity) ' после mapValues (поэтому нет необходимости в реализации конкретной функции):

scala> val xs = Map("a" -> 1, "b" -> 2)
xs: scala.collection.immutable.Map[java.lang.String,Int] = Map(a -> 1, b -> 2)

scala> val ys = xs.mapValues(_ + Random.nextInt).map(identity)
ys: scala.collection.immutable.Map[java.lang.String,Int] = Map(a -> 1315230132, b -> 1614948101)

scala> ys
res7: scala.collection.immutable.Map[java.lang.String,Int] = Map(a -> 1315230132, b -> 1614948101)

жаль, что тип вернулся на самом деле это не вид! иначе можно было бы назвать это "силой"...

Comments

    Ничего не найдено.