我正在尝试在scala中找到assoc-in(clojure)的等效项。我正在尝试转换
(defn- organiseDataByTradeId [data]
(reduce #(let [a (assoc-in %1
[(%2 "internaltradeid") (read-string (%2 "paramseqnum")) "levelcols"]
(reduce (fn [m k](assoc m k (get %2 k)))
{}
(string/split xmlLevelAttributesStr #",")))
b (assoc-in a
[(%2 "internaltradeid") (read-string (%2 "paramseqnum")) "subLevelCols" (read-string (%2 "cashflowseqnum"))]
(reduce (fn [m k] (assoc m k (get %2 k)))
{}
(string/split xmlSubLevelAttributesStr #","))
)]
b)
{}
data))
进入scala。 尝试过这个:
def organiseDataByTradeId(data: List[Map[String, String]]) = {
data.map { entry => Map(entry("internaltradeid") -> Map(entry("paramseqnum").toInt -> Map("levelcols" -> (xmlLevelAttributesStr.split(",")).map{key=> (key,entry(key))}.toMap,
"subLevelCols" -> Map(entry("cashflowseqnum").asInstanceOf[String].toInt -> (xmlSubLevelAttributesStr.split(",")).map{key=> (key,entry(key))}.toMap)))) }
}
不确定如何在不覆盖的情况下合并我得到的地图列表。 这里 data 列表[Map [String,String]] 基本上是描述一个表。每个条目都是一行。列名是映射的键,值是值。 strong> xmlLevelAttributeStr 和 xmlSubLevelAttributeStr 是两个字符串,其中列名之间用逗号分隔。 我对scala还是陌生的。我将每一行(Map [String,String])转换为一个Scala Map,现在不知道如何合并它们,这样以前的数据就不会被覆盖并且行为与clojure代码完全相同。此外,我也不允许使用外部库,例如斯卡拉兹。
答案 0 :(得分:1)
此Clojure代码不是一个很好的复制模式:它有很多重复项,并且很少解释它在做什么。我会这样写:
(defn- organiseDataByTradeId [data]
(let [level-reader (fn [attr-list]
(let [levels (string/split attr-list #",")]
(fn [item]
(into {} (for [level levels]
[level (get item level)])))))
attr-levels (level-reader xmlLevelAttributesStr)
sub-levels (level-reader xmlSubLevelAttributesStr)]
(reduce (fn [acc item]
(update-in acc [(item "internaltradeid"),
(read-string (item "paramseqnum"))]
(fn [trade]
(-> trade
(assoc "levelcols" (attr-levels item))
(assoc-in ["subLevelCols", (read-string (item "cashflowseqnum"))]
(sub-levels item))))))
{}, data)))
比原始代码多了几行代码,但是我借此机会命名了许多有用的概念,并将重复内容提取到局部函数中,以使其更加不言自明。
如果您知道将不会重复使用内部贸易编号,那就更容易了:您可以简单地生成许多独立的图并将它们合并在一起:
(defn- organiseDataByTradeId [data]
(let [level-reader (fn [attr-list]
(let [levels (string/split attr-list #",")]
(fn [item]
(into {} (for [level levels]
[level (get item level)])))))
attr-levels (level-reader xmlLevelAttributesStr)
sub-levels (level-reader xmlSubLevelAttributesStr)]
(apply merge (for [item data]
{(item "internaltradeid")
{(read-string (item "paramseqnum"))
{"levelcols" (attr-levels item),
"subLevelCols" {(read-string (item "cashflowseqnum")) (sub-levels item)}}}}))))
但是,实际上,这两种方法都不适合在Scala中使用,因为Scala与Clojure具有不同的数据建模原理。 Clojure鼓励像这样宽松定义的异构地图,Scala希望您的地图是同质的。当您需要将多种类型的数据混合在一起时,Scala建议您定义一个类(或者也许是一个案例类-我不是Scala专家),然后创建该类的实例。
因此,在这里您需要一个Map[String, Map[Int, TradeInfo]]
,其中TradeInfo
是一个具有两个字段levelcols : List[Attribute]
和subLevelCols
作为类对的类(或者可能是一个单元素映射),其中包含一个cashflowseqnum
和另一个List[Attribute]
。
一旦您以Scala方式对数据建模,就不会使用任何看起来像assoc-in
的东西了,因为您的数据将不会是一张巨大的地图,因此问题就不会出现了。出现。