Scala. Добавить к значению карты, которое является ListBuffer - PullRequest
0 голосов
/ 28 апреля 2020

У меня есть пустая Карта с пустым ListBuffer в качестве значения по умолчанию.

val map: Map[String, ListBuffer[String]] = Map.empty.withDefaultValue(ListBuffer())

Когда я обращаюсь к еще не существующим ключам и хочу добавить некоторые значения, это делает что-то неожиданное:

// map += "one" -> ListBuffer("l")
map("one") += "lo"
map("two") += "lol"
map("one") += "la"

println(map("one").result)

Я думал, что это должно вывести List(lo, la), но это печатает List(lo, lol, la).
for(m <- map) println(m) ничего не печатает.
Если я раскомментирую map += "one" -> ListBuffer("t"), он печатает List(l, lo, la), что правильно, но println("two(or any other key)") печатает List(lo, lol, la).
Как это исправить ? Есть что-то, о чем я не знаю?

Ответы [ 2 ]

2 голосов
/ 28 апреля 2020

это происходит потому, что ваша карта имеет значение по умолчанию - ListBuffer(), когда вы пытаетесь добавить что-то к карте: map("one") += "lo" фактически карта искала ключ one, ничего не нашла и получает значение по умолчанию - ListBuffer(). После этого lo добавляется к ListBuffer() и значение по умолчанию теперь равно ListBuffer("lo"). То же самое go повторяется для клавиш two и one. Таким образом, ключ one (и остальные ключи также) никогда не будет помещен на карту.

Также вы используете неизменяемую карту, и она добавляет новую карту после добавления. Если вы хотите собрать карту со всеми ключами и значениями, вы можете использовать foldLeft:

val map: Map[String, ListBuffer[String]] = Map.empty.withDefaultValue(ListBuffer())
val newMap = Seq(
  "one" -> "lo",
  "two" -> "lol",
  "one" -> "la"
).foldLeft(map){
  case (accMap, (key, value)) => accMap + (key -> (value +: accMap(key)))
}
println(newMap("one").result) // List(la, lo)
println(newMap) // Map(one -> ListBuffer(la, lo), two -> ListBuffer(lol))

или использовать изменяемую карту:

val map: mutable.Map[String, ListBuffer[String]] = mutable.Map.empty.withDefaultValue(ListBuffer())
map.update("one",  "lo" +: map("one"))
map.update("two",  "lol" +: map("two"))
map.update("one",  "la" +: map("one"))
println(map("one").result) // List(la, lo)
println(map) // Map(one -> ListBuffer(la, lo), two -> ListBuffer(lol))
1 голос
/ 28 апреля 2020

если у вас есть последовательность кортежей, как это

val keyValue = Seq( "one" -> "lo", "two" -> "lol", "one" -> "la" )

я бы предложил вам использовать groupBy как это

println(x.groupBy(_._1).mapValues(_.map(_._2)))

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

почему вы не получаете желаемого результата из своего кода, потому что у вас есть неизменяемая карта, если вы хотите чтобы обновить карту, вам нужно иметь изменяемую карту, которая предоставляет вам обновление метода, здесь вы принимаете map("one") += "la" здесь, что происходит, вы получаете listBuffer, когда вы делаете карту ("one"), которая пуста, то вы обновляете это listBuffer с "lo" с использованием += и то же самое с "two" and "one" Но если вы увидите, что ваша карта все еще пуста, то на карте ничего нет, потому что вы не обновили карту, вы обновили listBuffer. Который вы получаете от map("one"), который является пустым listBuffer.

вы получите тот же результат, если будете использовать любую строку в печати, как

println(map("").result) //List("lo", "lol", "la")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...