Как получить значение вложенной карты, используя значение первой карты? - PullRequest
3 голосов
/ 02 июля 2019

У меня есть карта записей типа Map [String, String] и карта поиска типа Map [String, Map [String, String]].Моя цель - найти совпадение во второй карте на первой карте, и когда у меня есть совпадение ключей, мне нужно заменить значение в первом словаре поиском второго словаря.Пример прояснит ситуацию.

До сих пор я придумал алгоритм, но получаю странный ответ Some (e) и Some (t).

Первая записькарта выглядит следующим образом:

val entries = Map("fruit" -> "aaa", "animal" -> "bbb", "person" -> "jjj")

Вторая карта выглядит следующим образом:

val lookup = Map("fruit" -> Map("ccc" -> "orange", "aaa" -> "apple"),
                 "animal" -> Map("zzz" -> "dog", "bbb" -> "cat"))

Ожидается следующий результат (примечание: «персона» не была правильно включена врезультат, поскольку для него нет соответствия):

val result = Map("fruit" -> "apple", "animal" -> "cat")

Алгоритм, который я придумал, следующий:

val res = for{ (k, ev) <- entries 
      lv <- lookup.get(k).get(ev)} yield (k, lv)

этот алгоритм дает мне следующий результат, и я понятия не имею,почему:

Map(fruit -> e, animal -> t)

Откуда взялись e и t?

Ответы [ 5 ]

5 голосов
/ 02 июля 2019

Разбейте его на составные части.

for {
  (k,v1) <- entries
  submap <- lookup.get(k)
  v2     <- submap.get(v1)
} yield (k,v2)
//res0: immutable.Map[String,String] = Map(fruit -> apple, animal -> cat)

Не уверен, откуда e и t приходят в выводе вашей ошибки.


OK,Я понял.lv <- lookup.get(k).get(ev) выполняет итерацию по каждой букве "apple" и "cat" соответственно, но, поскольку для каждого ключа в Map может быть только одна пара ключ-> значение, сохраняется только последняя буква.

1 голос
/ 02 июля 2019

Документация для yield объясняет, почему это происходит: https://docs.scala -lang.org / tutorials / FAQ / yield.html

Страница в Примере 2 гласит:

for(x <- c1; y <- c2; z <- c3) yield {...}
is translated into
c1.flatMap(x => c2.flatMap(y => c3.map(z => {...})))

Поэтому ваше понимание означает:

entries.flatMap({case (k, ev) => lookup.get(k).get(ev).map(lv => (k, lv)) })

Ключевым моментом здесь является то, что каждое из «apple» и «cat» - это строки, над которыми выполняется map (т.е. вы перебираете каждый символ этих слов). Поскольку Map обновляется с помощью ("fruit" -> "a") ... ("fruit" -> "e"), становится очевидным только (fruit -> e), а конечный результат - это то, что вы видели:

Map(fruit -> e, animal -> t)

Некоторые способы получить желаемый результат:

for{ (k, ev) <- entries ;lv <- lookup.get(k)} yield (k, lv.get(ev).get)

Или вообще избегайте цепочечного понимания, и просто используйте обычный map:

entries.map({case (k, v) => (k, lookup.get(k).get(v))})

Оба эти результата приводят к Map(fruit -> apple, animal -> cat), но обратите внимание, что эти решения не обрабатывают случай, когда get возвращает None (т. Е. В карте поиска отсутствует этот ключ)

1 голос
/ 02 июля 2019

Это будет работать:

val res = for{ 
    (k, ev) <- entries
    l1 <- lookup.get(k)
    l2 <- l1.get(ev)
} yield { 
    (k, lv)
}

Неисправность Объяснение:

lookup.get(k).get(ev) //this returns a String <- reason: not known

x <- "apple" //x is now a List[Char] -> List('a','p','p','l','e')

Сейчас:

map += ("animal" -> 'a')
map += ("animal" -> 'p')
map += ("animal" -> 'p')
map += ("animal" -> 'l')
map += ("animal" -> 'e')
map += ("fruit" -> 'c')
map += ("fruit" -> 'a')
map += ("fruit" -> 't')

В результате:

Map("animal" -> 'e', "fruit", 't')
0 голосов
/ 02 июля 2019

Встроенное решение:

val res =  entries.flatMap(e => lookup.get(e._1).flatMap(_.get(e._2).map(e._1->_)))

Выход:

res: scala.collection.immutable.Map[String,String] = Map(fruit -> apple, animal -> cat)
0 голосов
/ 02 июля 2019

Вы также можете попробовать следующий подход для получения вывода

val output = entries.map{
  case (k,v) =>
    k -> lookup.get(k).flatMap(_.get(v)).getOrElse(v)
}

Это выведет вам вывод как

output: scala.collection.immutable.Map[String,String] = Map(fruit -> apple, animal -> cat)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...