【问题标题】:Scala Compare Map value to another Map keyScala 将 Map 值与另一个 Map 键进行比较
【发布时间】:2019-04-20 16:47:51
【问题描述】:

我有两张地图:

val myMap1 = Map(
    testKey1 -> List(testValue1, testValue2, testValue3....), 
    testKey2 -> List(testValue4, testValue5, testValue6....),
    testKey3 -> List(testValue7, testValue8, testValue9....)     
    testKey4 -> List(testValue10, testValue11, testValue12....)     
)

val myMap2 = Map(
        testValue1 -> List(Value1, Value2, Value3....), 
        testValue5 -> List(Value4, Value5, Value6....),
        testValue10 -> List(Value7, Value8, Value9....)
    )

我想通过将 Map1 值与 Map2 键匹配来创建第三个 Map,

其中 Map1 的键将是 Key,Map2 的值将是这个新的第三个 Map 的值。

应该是这样的

val myMap3 = Map(
        testKey1 -> List(Value1, Value2, Value3....), 
        testKey2 -> List(Value4, Value5, Value6....),
        testKey4 -> List(Value7, Value8, Value9....)
    )

我未能遍历作为列表的 Map1 值并获取该值的相应键。

【问题讨论】:

  • 为什么testKey3 被删除而testKey4 被保留?这样做的逻辑是什么?
  • testKey3 的值不在myMap2 的键中
  • 啊,明白了。那么当testValueX 出现在 2 个或更多键下时会发生什么?

标签: scala


【解决方案1】:

您可以通过在第一个 Map 上使用 mapValues 来获得所需的值的键的每个 List,然后在此 lis 上使用 flatMap获得所需的值。
这是一个示例,请注意getOrElse 方法,以确保我们始终获得一个值,即使该键不存在。

val myMap1 = Map(
  "testKey1" -> List("testValue1", "testValue2", "testValue3"), 
  "testKey2" -> List("testValue4", "testValue5", "testValue6"),
  "testKey3" -> List("testValue7", "testValue8", "testValue9"),
  "testKey4" -> List("testValue10", "testValue11", "testValue12")     
)

val myMap2 = Map(
  "testValue1" -> List(1, 2, 3), 
  "testValue2" -> List(5), 
  "testValue5" -> List(4, 5, 6),
  "testValue10" -> List(7, 8, 9)
)

val myMap3 = myMap1.mapValues {
  valuesList => valuesList.flatMap {
    valueKey => myMap2.getOrElse(valueKey, List.empty[Int])
  }
}

// myMap3: Map[String, List[Int]] = Map(
//   testKey1 -> List(1, 2, 3, 5),
//   testKey2 -> List(4, 5, 6),
//   testKey3 -> List(),
//   testKey4 -> List(7, 8, 9)
// )

如果您需要删除具有空值的键,您可以进行过滤。
myMap3.filter { case (_, values) => values.nonEmpty }

编辑

如果我想创建这个 myMap3,其中的值将是 myMap2 的键和它们各自的值。

鉴于myMap1 的值是myMap2 列表,我认为您真正想要的是Map[String, Map[String, List[A]]

val myMap4 = myMap1.mapValues {
  valuesList => valuesList.map {
    valueKey => valueKey -> myMap2.getOrElse(valueKey, List.empty[Int])
  }.toMap
}

// myMap4: Map[String, Map[String, List[Int]]] = Map(
//   testKey1 -> Map(testValue1 -> List(1, 2, 3), testValue2 -> List(5), testValue3 -> List()),
//   testKey2 -> Map(testValue4 -> List(), testValue5 -> List(4, 5, 6), testValue6 -> List()),
//   testKey3 -> Map(testValue7 -> List(), testValue8 -> List(), testValue9 -> List()),
//   testKey4 -> Map(testValue10 -> List(7, 8, 9), testValue11 -> List(), testValue12 -> List())
// )

同样,您可以过滤不需要的空值。

val myMap5 = myMap1.mapValues {
  valuesList => valuesList.flatMap { // here we use flatMap, to filter any None.
    valueKey => myMap2.get(valueKey).map(values => valueKey -> values)
  }.toMap
} filter {
  case (_, values) => values.nonEmpty
}

// myMap5: Map[String, Map[String, List[Int]]] = Map(
//   testKey1 -> Map(testValue1 -> List(1, 2, 3), testValue2 -> List(5)),
//   testKey2 -> Map(testValue5 -> List(4, 5, 6)),
//   testKey4 -> Map(testValue10 -> List(7, 8, 9))
// )

【讨论】:

  • 不错,但可以压缩:myMap1.mapValues(_.flatMap(myMap2.get))
  • @jwvh 好吧,我更喜欢使用明确的名称,而不是使用_ (但是,正如我所说,这只是我个人的喜好)。但是,由于您使用get flatMap 将返回List[List[A]] 而不是普通的List[A] (这是我认为操作需要的),当然可以调用.flattenflatMap 之后,但我认为这只是一个不必要的额外迭代。
  • @LuisMiguelMejíaSuárez 非常感谢。它运行良好。虽然我在 scala 和函数式编程方面非常陌生,但代码对我来说有点难。我还有一个问题,如果我想创建这个 myMap3,其中的值将是 myMap2 的键和它们各自的值。像这样:val myMap3 = Map( testKey1 -> testValue1 -> List(1, 2, 3, 5), testKey2 -> testValue5 -> List(4, 5, 6), testKey4 -> testValue10 ->List(7, 8, 9) )
  • @AshiqurRahman 我已经更新了答案,希望对您有所帮助。如果您有任何其他简单的问题,请不要怀疑将其作为评论提出 - 但是,如果该问题暗示代码逻辑的另一个变化,我相信最好是在网站上提出另一个问题。作为一个建议,我建议你参加任何 Scala 入门课程,你会发现用 mapflatMapfilter 而不是 iterate 来转换集合并不难- 另外,对我来说,从类型、输入内容与输出内容以及代码流等方面进行思考对我有很大帮助。
  • @LuisMiguelMejíaSuárez 非常感谢您的回复和建议。陛下,我会遵守的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-22
相关资源
最近更新 更多