scala groupby 按地图列表中地图的值
scala groupby by the value of the map in a list of maps
所以我有一个 maps 这样的列表
val data = List(
Map[String, String]("name" -> "Bob", "food" -> "pizza", "day" -> "monday"),
Map[String, String]("name" -> "Ron", "food" -> "hotdog", "day" -> "tuesday"),
Map[String, String]("name" -> "Tim", "food" -> "pizza", "day" -> "wednesday"),
Map[String, String]("name" -> "Carl", "food" -> "hotdog", "day" -> "wednesday")
)
我想根据 maps
的列表制作这样的地图
val result = Map("pizza" -> Map("name" -> ("Bob", "Tim"), "day" -> ("monday", "wednesday")),
"hotdog"-> Map("name" -> ("Ron", "Carl"), "day" -> ("tuesday", "wednesday")))
我怎样才能达到这个结果?谢谢
*ps 我是 Scala 的初学者
这是一个初步的解决方案,使用 fold
可能有更简单的方法,但我必须单独勾勒出来
data.groupMap(a => a("food"))(_.filter(_._1 != "food"))
.map{
case (a,b) =>
(a, b.flatten.groupMapReduce(_._1)(a => List(a._2))(_ ++ _))}
- 您根据
food
的值对内部地图进行分组
这给你:
Map(
hotdog -> List(
Map(name -> Ron, food -> hotdog, day -> tuesday),
Map(name -> Carl, food -> hotdog, day -> wednesday)),
pizza -> List(
Map(name -> Bob, food -> pizza, day -> monday),
Map(name -> Tim, food -> pizza, day -> wednesday))
)
- 您从内部映射
中删除了密钥food
Map(
hotdog -> List(
Map(name -> Ron, day -> tuesday),
Map(name -> Carl, day -> wednesday)),
pizza -> List(
Map(name -> Bob, day -> monday),
Map(name -> Tim, day -> wednesday))
)
您使用 groupMapReduce
和
“合并”里面的地图
a) 按内键分组(即 name
和 day
)
b) 将每个值映射到一个单例列表
c) 连接列表
编辑:这是一个使用 foldLeft
的单通道解决方案,但我不认为我更喜欢这个。所有的密钥访问都是不安全的,如果您输入的密钥丢失,将会崩溃。所以理想情况下你需要使用 .get()
来取回一个选项并做一堆模式匹配
data.foldLeft(Map[String, Map[String, List[String]]]())((b, a) => {
val foodVal = a("food")
b.get(foodVal) match{
case None => b + (foodVal ->
List("name" -> List(a("name")), "day" -> List(a("day"))).toMap)
case Some(v : Map[String, List[String]]) =>
b + (foodVal ->
List("name" -> (v("name") :+ a("name")), "day" -> (v("day") :+ a("day"))).toMap)
}
})
所以我有一个 maps 这样的列表
val data = List(
Map[String, String]("name" -> "Bob", "food" -> "pizza", "day" -> "monday"),
Map[String, String]("name" -> "Ron", "food" -> "hotdog", "day" -> "tuesday"),
Map[String, String]("name" -> "Tim", "food" -> "pizza", "day" -> "wednesday"),
Map[String, String]("name" -> "Carl", "food" -> "hotdog", "day" -> "wednesday")
)
我想根据 maps
的列表制作这样的地图val result = Map("pizza" -> Map("name" -> ("Bob", "Tim"), "day" -> ("monday", "wednesday")),
"hotdog"-> Map("name" -> ("Ron", "Carl"), "day" -> ("tuesday", "wednesday")))
我怎样才能达到这个结果?谢谢
*ps 我是 Scala 的初学者
这是一个初步的解决方案,使用 fold
可能有更简单的方法,但我必须单独勾勒出来
data.groupMap(a => a("food"))(_.filter(_._1 != "food"))
.map{
case (a,b) =>
(a, b.flatten.groupMapReduce(_._1)(a => List(a._2))(_ ++ _))}
- 您根据
food
的值对内部地图进行分组
这给你:
Map(
hotdog -> List(
Map(name -> Ron, food -> hotdog, day -> tuesday),
Map(name -> Carl, food -> hotdog, day -> wednesday)),
pizza -> List(
Map(name -> Bob, food -> pizza, day -> monday),
Map(name -> Tim, food -> pizza, day -> wednesday))
)
- 您从内部映射 中删除了密钥
food
Map(
hotdog -> List(
Map(name -> Ron, day -> tuesday),
Map(name -> Carl, day -> wednesday)),
pizza -> List(
Map(name -> Bob, day -> monday),
Map(name -> Tim, day -> wednesday))
)
您使用
“合并”里面的地图groupMapReduce
和a) 按内键分组(即
name
和day
)b) 将每个值映射到一个单例列表
c) 连接列表
编辑:这是一个使用 foldLeft
的单通道解决方案,但我不认为我更喜欢这个。所有的密钥访问都是不安全的,如果您输入的密钥丢失,将会崩溃。所以理想情况下你需要使用 .get()
来取回一个选项并做一堆模式匹配
data.foldLeft(Map[String, Map[String, List[String]]]())((b, a) => {
val foodVal = a("food")
b.get(foodVal) match{
case None => b + (foodVal ->
List("name" -> List(a("name")), "day" -> List(a("day"))).toMap)
case Some(v : Map[String, List[String]]) =>
b + (foodVal ->
List("name" -> (v("name") :+ a("name")), "day" -> (v("day") :+ a("day"))).toMap)
}
})