计算 scala 2 中按键分组的几个映射中键值的出现次数。11.x

Count occurence of key values from several maps grouped by a key in scala 2.11.x

设想以下地图列表(可能更长):

List(
Map[String,String]("wind"->"high", "rain"->"heavy", "class"->"very late"),
Map[String,String]("wind"->"none", "rain"->"slight", "class"->"on time"),
Map[String,String]("wind"->"high", "rain"->"none", "class"->"very late"),
...
)

我怎样才能得到下面的表格:

Map("very late" -> Set(("wind",Map("high" -> 2)), ("rain",Map("heavy" -> 1, "none" -> 1))),
"on time" -> Set(("wind",Map("none" -> 1)), ("rain",Map("slight" -> 1))))

这里有两个版本。

首先使用 Set,这看起来像你想要的,

val grouped2 = maps.foldLeft(Map.empty[String, Set[(String, Map[String, Int])]]) {
  case (acc, map) =>
    map.get("class").fold(acc) { key =>
      val keyOpt = acc.get(key)
      if (keyOpt.isDefined) {
        val updatedSet = (map - "class").foldLeft(Set.empty[(String, Map[String, Int])]) {
          case (setAcc, (k1, v1)) =>
            keyOpt.flatMap(_.find(_._1 == k1)).map { tup =>
              setAcc + ((k1, tup._2.get(v1).fold(tup._2 ++ Map(v1 -> 1))(v => tup._2 + ((v1, v + 1)))))
            }.getOrElse(setAcc + (k1 -> Map(v1 -> 1)))
        }
        acc.updated(key, updatedSet)
      } else {
        acc + (key -> (map - "class").map(tup => (tup._1, Map(tup._2 -> 1))).toSet)
      }
    }
}

然后使用 Map,

val grouped1 = maps.foldLeft(Map.empty[String, Map[String, Map[String, Int]]]) {
  case (acc, map) =>
    map.get("class").fold(acc) { key =>
      val keyOpt = acc.get(key)
      if (keyOpt.isDefined) {
        val updatedMap = (map - "class").foldLeft(Map.empty[String, Map[String, Int]]) {
          case (mapAcc, (k1, v1)) =>
            keyOpt.flatMap(_.get(k1)).map{ statMap =>
              mapAcc + ((k1, statMap.get(v1).fold(statMap ++ Map(v1 -> 1))(v => statMap + ((v1, v + 1)))))
            }.getOrElse(mapAcc + (k1 -> Map(v1 -> 1)))
        }
        acc.updated(key, updatedMap)
      } else {
        acc + (key -> (map - "class").map(tup => (tup._1, Map(tup._2 -> 1))))
      }
    }
}

我是playing withMap版本,改成了Set。过几天,我想我不会光看上面的都明白。所以,我试图让它对我来说尽可能容易理解。将此调整为您自己的解决方案或等待其他解决方案。

这会让你得到你想要的。

val maps = List(...)

maps.groupBy(_.getOrElse("class","no-class"))
  .mapValues(_.flatMap(_ - "class").groupBy(_._1)
    .mapValues(_.map(_._2).groupBy(identity)
      .mapValues(_.length)
    ).toSet
  )

问题是,你想要的不是一个好地方。

结果类型是Map[String,Set[(String,Map[String,Int])]],这是一个可怕的集合类型大杂烩。为什么 Set?这样做的目的是什么?这有什么用?您如何从中检索有意义的数据?

这看起来像 XY problem

这是另一个实现,它使用 MapkeySet 方法将两个映射连接在一起。
另外,请注意,我将输出类型从 Map 更改为 Set 元组,其第二个值是另一个 Map。三个嵌套 Maps,恕我直言,这更有意义。

def groupMaps[K, V](groupingKey: K, data: List[Map[K, V]]): Map[V, Map[K, Map[V, Int]]] =
  data.foldLeft(Map.empty[V, Map[K, Map[V, Int]]]) {
    case (acc, map) =>
      map.get(key = groupingKey).fold(ifEmpty = acc) { groupingValue  =>
        val newValues = (map - groupingKey).map {
          case (key, value) =>
            key -> Map(value -> 1)
        }
        
        val finalValues = acc.get(key = groupingValue).fold(ifEmpty = newValues) { oldValues =>
          (oldValues.keySet | newValues.keySet).iterator.map { key =>
            val oldMap = oldValues.getOrElse(key = key, default = Map.empty[V, Int])
            val newMap = newValues.getOrElse(key = key, default = Map.empty[V, Int])
            
            val finalMap = (oldMap.keySet | newMap.keySet).iterator.map { value =>
              val oldCount = oldMap.getOrElse(key = value, default = 0)
              val newCount = newMap.getOrElse(key = value, default = 0)
              
              value -> (oldCount + newCount)
            }.toMap
            
            key -> finalMap
          }.toMap
        }
        
        acc.updated(key = groupingValue, finalValues)
      }
  }

可以这样使用:

val maps =
  List(
    Map("wind" -> "none", "rain" -> "none", "class" -> "on time"),
    Map("wind" -> "none", "rain" -> "slight", "class" -> "on time"),
    Map("wind" -> "none", "rain" -> "slight", "class" -> "late"),
    Map("wind" -> "none", "rain" -> "slight")
  )
val result = groupMaps(groupingKey = "class", maps)
// val result: Map[Strig, Map[String, Map[String, Int]]] =
//  Map(
//    on time -> Map(wind -> Map(none -> 2), rain -> Map(none -> 1, slight -> 1)),
//    late -> Map(wind -> Map(none -> 1), rain -> Map(slight -> 1))
//  )

如果你需要保持你要求的输出类型,那么你可以在 foldLeft

的末尾做一个 .mapValue(_.toSet)

可以看到代码运行 here