如何将复杂的对象列表转换为 Scala 中的地图
How to convert complex list of objects into the map in Scala
我正在寻找将我的案例对象列表转换为地图的方法。这个
输入class看起来像这样
case class MyData(
source: String,
dataMap: Map[String, String]
)
结果classpost-转化
case class LiverampMappingV2(
dataMapping: Map[String, Map[String, Seq[String]]]
)
例如输入数据如下 -->
val data = List(
new myData("abc.com", Map("key1" -> "value1", "key2" -> "value2")),
new myData("abc.com", Map("key1" -> "value11", "key3" -> "value3")),
new myData("pqr.com", Map("key1" -> "value111", "key3" -> "value33"))
)
将拼装如下
Map(
key1 -> Map("abc.com" -> List("value1", "value11"), "pqr.com" -> List("value111")),
key2 -> Map("abc.com" -> List("value2")),
key3 -> Map("abc.com" -> List("value13"), "pqr.com" -> List("value33"))
)
我尝试了几个选项,使用 groupBy
和 groupMap
的组合,然后是 flatten
但是作为 scala 和函数式编程的新手,我无法找到最终的解决方案.
感谢任何帮助或指导。
如果范围内有 cats,这很简单,因为您可以利用 Map
的 Monoid
import cats.syntax.all._
def groupByNested(data: List[MyData]): Map[String, Map[String, List[String]]] =
data.foldMap {
case MyData(source, dataMap) =>
dataMap.map {
case (key, value) =>
key -> Map(source -> (value :: Nil))
}
}
I am not totally happy with the function name.
可以看到运行here.
如果范围内没有猫,我也可以推荐另一种方法 :D
虽然这很冗长而且有点复杂。
那是因为您需要在每次迭代时折叠第一个原始“数据”。
但我会尽力解释:
type MP = Map[String, List[String]]
// just for shortening the code, you can put a better name on it
data.foldLeft[Map[String, MP]](Map.empty)(
(agg, newData) => {
val source = newData.source
newData.dataMap.foldLeft(agg) {
case (updatingAggregator, (key, value)) =>
updatingAggregator.updatedWith(key) {
case Some(existingMap) =>
Some(existingMap.updatedWith(source) {
case Some(existingList) => Some(value :: existingList)
case None => Some(value :: Nil)
})
case None =>
Some(Map(source -> (value :: Nil)))
}
}
}
)
基本上我们在这里做的是折叠 data
,零值为 empty Map of String to MP
(这是我们希望从算法和折叠中得到的结果类型)。在每次迭代中,您都有源 (val source = ...
)。您还有一个数据映射,您需要再次折叠它 (:D),并使用给定的源、键和值更新之前在其中创建的 agg
值。现在在 updatedWith 方法中,您基本上是在 updatingAggregator 中寻找 source
,如果它已经有了,您只需在前面添加值,如果没有,您就添加它。
如果描述不够清楚,请告诉我。
我正在寻找将我的案例对象列表转换为地图的方法。这个
输入class看起来像这样
case class MyData(
source: String,
dataMap: Map[String, String]
)
结果classpost-转化
case class LiverampMappingV2(
dataMapping: Map[String, Map[String, Seq[String]]]
)
例如输入数据如下 -->
val data = List(
new myData("abc.com", Map("key1" -> "value1", "key2" -> "value2")),
new myData("abc.com", Map("key1" -> "value11", "key3" -> "value3")),
new myData("pqr.com", Map("key1" -> "value111", "key3" -> "value33"))
)
将拼装如下
Map(
key1 -> Map("abc.com" -> List("value1", "value11"), "pqr.com" -> List("value111")),
key2 -> Map("abc.com" -> List("value2")),
key3 -> Map("abc.com" -> List("value13"), "pqr.com" -> List("value33"))
)
我尝试了几个选项,使用 groupBy
和 groupMap
的组合,然后是 flatten
但是作为 scala 和函数式编程的新手,我无法找到最终的解决方案.
感谢任何帮助或指导。
如果范围内有 cats,这很简单,因为您可以利用 Map
Monoid
import cats.syntax.all._
def groupByNested(data: List[MyData]): Map[String, Map[String, List[String]]] =
data.foldMap {
case MyData(source, dataMap) =>
dataMap.map {
case (key, value) =>
key -> Map(source -> (value :: Nil))
}
}
I am not totally happy with the function name.
可以看到运行here.
如果范围内没有猫,我也可以推荐另一种方法 :D 虽然这很冗长而且有点复杂。 那是因为您需要在每次迭代时折叠第一个原始“数据”。 但我会尽力解释:
type MP = Map[String, List[String]]
// just for shortening the code, you can put a better name on it
data.foldLeft[Map[String, MP]](Map.empty)(
(agg, newData) => {
val source = newData.source
newData.dataMap.foldLeft(agg) {
case (updatingAggregator, (key, value)) =>
updatingAggregator.updatedWith(key) {
case Some(existingMap) =>
Some(existingMap.updatedWith(source) {
case Some(existingList) => Some(value :: existingList)
case None => Some(value :: Nil)
})
case None =>
Some(Map(source -> (value :: Nil)))
}
}
}
)
基本上我们在这里做的是折叠 data
,零值为 empty Map of String to MP
(这是我们希望从算法和折叠中得到的结果类型)。在每次迭代中,您都有源 (val source = ...
)。您还有一个数据映射,您需要再次折叠它 (:D),并使用给定的源、键和值更新之前在其中创建的 agg
值。现在在 updatedWith 方法中,您基本上是在 updatingAggregator 中寻找 source
,如果它已经有了,您只需在前面添加值,如果没有,您就添加它。
如果描述不够清楚,请告诉我。