Почему .map.flatten и flatMap на карте Scala дают разные результаты?

Вы не можете и не должны полагаться на упорядочение элементов в объекте JSON.

Из спецификации JSON в http://www.json.org/

Объект является неупорядоченным набором пар имя / значение

. Как следствие, библиотеки JSON могут изменять порядок элементов по своему усмотрению. Это не ошибка.

2
задан Sietse 17 January 2019 в 08:01
поделиться

3 ответа

Здесь вы как бы неправильно понимаете вещи,

Итак, допустим, у вас есть x: M[A] и f: A = N[B] для любых Monad, M и N, тогда x.flatMap(f) должно быть таким же, как x.map(f).flatten.

Но здесь у вас есть своего рода вложенная монада map: M[N[A]], и ваша функция - f: A => B с последующим псевдонимом,

scala> type MapWithStringKey[A] = Map[String, A]
// defined type alias MapWithStringKey

scala> type TupleOfInt = (Int, Int)
// defined type alias TupleOfInt

scala> val map: MapWithStringKey[List[TupleOfInt]] = Map("a" -> List(1 ->11,1->111), "b" -> List(2 -> 22, 2 ->222))
// map: MapWithStringKey[List[TupleOfInt]] = Map(a -> List((1,11), (1,111)), b -> List((2,22), (2,222)))

. Этот случай полностью отличается от упомянутого выше стандартного определения, связывающего [ 1110] до map и flatten.

Теперь, это только один из нестандартных случаев, когда вы можете выбрать любой из двух вариантов в зависимости от того, что вы хотите. И когда мы добавим специальные свойства уникальности ключа из Map (о чем мы уже говорили в ответе @ sepp2k), все становится еще более непредсказуемым.

0
ответ дан Sarvesh Kumar Singh 17 January 2019 в 08:01
поделиться

TL; DR: тип результата обоих вызовов различен. Вызов .map().flatten возвращает Iterable[(Int, Int)], а вызов .flatMap() возвращает Map[Int, Int]. Поскольку карта может не содержать один и тот же ключ дважды, первая запись на ключ заменяется второй записью.

Рассмотрим Map как Iterable[(Key,Value)]. При вызове .map вам нужно будет предоставить ему функцию, которая возвращает кортеж, (Key, Value) (фактические типы могут отличаться от оригинальных Key и Value).

В вашем примере, Value оказывается List[(Int, Int)]. Когда вы вызываете .map и возвращаете Value оригинала Map, вы в конечном итоге получаете Iterable[List[(Int, Int)]], который в результате обращения к .flatten превращается в Iterable[(Int, Int)], объединяя «внутренние» списки вместе. Если бы вы превратили это в карту (вызвав .toMap), вы бы увидели тот же результат, что и с flatMap.

Теперь flatMap отличается тем, что ожидает тип возвращаемого значения Seq[(Key, Value)], а не просто (Key, Value). Затем он использует возвращенное значение в качестве записей во вновь построенном Map.

В вашем случае ваш исходный Value из List[(Int, Int)] удовлетворяет ожидаемому типу возврата, превращая ваш исходный Map[(String, List[(Int, Int)] в Map[(Int, Int)]. Поскольку карта не может содержать две записи с одинаковыми ключами, второе вхождение ключа заменяет более раннее вхождение.

Чтобы увидеть это поведение, полезно использовать REPL (просто запустите scala) вместо написания основного класса, чтобы вы могли видеть промежуточные значения и их типы.

scala> val theMap = Map("a" -> List(1 ->11,1->111), "b" -> List(2 -> 22, 2 ->222))
theMap: scala.collection.immutable.Map[String,List[(Int, Int)]] = Map(a -> List((1,11), (1,111)), b -> List((2,22), (2,222)))

scala> val mapped = theMap.map(_._2)
mapped: scala.collection.immutable.Iterable[List[(Int, Int)]] = List(List((1,11), (1,111)), List((2,22), (2,222)))

scala> val flattened = mapped.flatten
flattened: scala.collection.immutable.Iterable[(Int, Int)] = List((1,11), (1,111), (2,22), (2,222))

scala> val flatMapped = theMap.flatMap(_._2)
flatMapped: scala.collection.immutable.Map[Int,Int] = Map(1 -> 111, 2 -> 222)

scala> val flattenedToMap = flattened.toMap
flattenedToMap: scala.collection.immutable.Map[Int,Int] = Map(1 -> 111, 2 -> 222)
0
ответ дан Sietse 17 January 2019 в 08:01
поделиться

При вызове .map(f) для Map с f, который возвращает (K, V) для некоторых K и V (не обязательно тех же типов K и V оригинала Map), результатом будет Map[K, V]. В противном случае, если f возвращает какой-либо другой (не парный) тип T, результатом будет Iterable[T]. Так что будет Map, если функция вернет пару, и Iterable в противном случае.

В вашем случае функция возвращает List[(Int, Int)], поэтому результатом является Iterable[List[(Int, Int)]], а не Map. .flatten затем превращает это в Iterable[(Int, Int)].

При непосредственном использовании flatMap вы напрямую получите пары (Int, Int), поэтому результатом будет Map[Int, Int], а не Iterable[(Int, Int)]. И поскольку Map не допускают дублирования ключей, Map содержит меньше элементов, чем Iterable.

0
ответ дан suish 17 January 2019 в 08:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: