Scala-在求和末求和

时间:2019-05-01 21:25:07

标签: scala

我有一个列表,我需要获得频率运算的总数作为结果末尾的附加元素。

scala> val a = List("decimal","string","string","decimal","timestamp","decimal", "timestamp" )
a: List[String] = List(decimal, string, string, decimal, timestamp, decimal, timestamp)

scala> a.foldLeft(Map[String,Int]().withDefaultValue(0)){ case (acc,x) =>  acc+(x->(acc(x)+1))  }
res103: scala.collection.immutable.Map[String,Int] = Map(decimal -> 3, string -> 2, timestamp -> 2)

我需要的是

Map(decimal -> 3, string -> 2, timestamp -> 2, total -> 7)

我可以使用下面的代码

Map("total" -> a.size) ++ a.foldLeft(Map[String,Int]().withDefaultValue(0)){ case (acc,x) =>  acc+(x->(acc(x)+1))  }

但是如何使用a.foldLeft( Map("total" -> 0 ) )实现。我正在尝试类似下面的操作,但出现错误。

scala> a.foldLeft( Map("total" -> 0 ) ){ case (acc,x) =>  acc+(x->(acc(x)+1))  }
java.util.NoSuchElementException: key not found: decimal
  at scala.collection.MapLike$class.default(MapLike.scala:228)
  at scala.collection.AbstractMap.default(Map.scala:59)
  at scala.collection.MapLike$class.apply(MapLike.scala:141)
  at scala.collection.AbstractMap.apply(Map.scala:59)

2 个答案:

答案 0 :(得分:4)

我认为这可以解决问题:

val a = List("decimal","string","string","decimal","timestamp","decimal", "timestamp" )
a.foldLeft(Map("total" -> 0).withDefaultValue(0)) (
  (acc,x) =>
    acc.updated(x,acc(x) + 1)
       .updated("total",acc("total") + 1)
)

编辑:我正在考虑:

  • 使用操作符+而不是为了简洁而对@jwvh的第一条评论
  • 通过删除显然不需要的"total" -> 0来@jwvh的第二条评论
  • 重构两个键的增量值。

解决方案变为:

def incrementValOfKeys(acc: Map[String, Int], keys: String*) = keys.foldLeft(acc)(
  (acc, key) => acc + (key -> (acc(key) + 1))
)

val a = List("decimal","string","string","decimal","timestamp","decimal", "timestamp" )
a.foldLeft(Map[String,Int]().withDefaultValue(0)) (incrementValOfKeys(_, _, "total"))

如果您想玩它:https://scalafiddle.io/sf/bAYBeNQ/0

incrementValOfKeys1递增Map[String, Int]的{​​{1}},每个键的值由acc给出。

这个想法是在keys中迭代地进行一次调用: crementValOfKeys(映射当前状态当前密钥,“总计”)

以下是foldLeft的一些示例,它们与您在问题中给出的主要incrementValOfKeys进行计算a的迭代步骤相对应:

  • foldLeft 给出incrementValOfKeys(Map[String, Int]().withDefaultValue(0), "decimal", "total")
  • Map("decimal" -> 1, "total" -> 1)给出incrementValOfKeys(Map[String, Int]("decimal" -> 1, "total" -> 1).withDefaultValue(0), "string", "total")
  • Map("decimal" -> 1, "total" -> 2, "string" -> 1)给出incrementValOfKeys(Map[String, Int]("decimal" -> 1, "total" -> 2, "string" -> 1).withDefaultValue(0), "string", "total")

如果您使用Map("decimal" -> 1, "total" -> 3, "string" -> 2)代替调用它,则不必使用incrementValOfKeys

答案 1 :(得分:3)

构建Map时无需累计总数,只需使用输入的size

a.groupBy(identity).map{case (k, v) => k -> v.size} + ("total" -> a.size)

注意

2.13中的集合库具有一个新的groupMapReduce方法,它将使此过程变得更加容易和有效,就像这样:

a.groupMapReduce(identity)(_ => 1)(_+_) + ("total" -> a.size)