Scala:如何在地图中使用fold *?

时间:2010-07-07 22:31:45

标签: scala

我有一个Map [String,String],并希望将这些值连接成一个字符串。

我可以看看如何使用List ...

来做到这一点
scala> val l = List("te", "st", "ing", "123")
l: List[java.lang.String] = List(te, st, ing, 123)

scala> l.reduceLeft[String](_+_)
res8: String = testing123

fold *或reduce *似乎是正确的方法我无法正确获得Map的语法。

2 个答案:

答案 0 :(得分:32)

在地图上折叠的工作方式与他们在对列表中的工作方式相同。您不能使用reduce,因为结果类型必须与元素类型(即一对)相同,但您需要一个字符串。因此,您将foldLeft与空字符串一起用作中性元素。您也不能只使用_+_,因为那时您会尝试将一对添加到字符串中。您必须改为使用一个函数来添加累积的字符串,该对的第一个值和该对的第二个值。所以你明白了:

scala> val m = Map("la" -> "la", "foo" -> "bar")                 
m: scala.collection.immutable.Map[java.lang.String,java.lang.String] = Map(la -> la, foo -> bar)

scala> m.foldLeft("")( (acc, kv) => acc + kv._1 + kv._2)
res14: java.lang.String = lalafoobar

折叠的第一个参数的说明:

如您所知,函数(acc, kv) => acc + kv._1 + kv._2有两个参数:第二个是当前正在处理的键值对。第一个是到目前为止累积的结果。但是,处理第一对时,acc的值是多少(尚未累积结果)?当您使用reduce时,acc的第一个值将是列表中的第一对(并且kv的第一个值将是列表中的第二个对)。但是,如果您希望结果的类型与元素类型不同,则不起作用。因此,我们使用fold来代替reduce,我们将acc的第一个值作为foldLeft的第一个参数传递。

简而言之:foldLeft的第一个参数说明了acc的起始值应该是什么。

正如Tom指出的那样,你应该记住,地图不一定要维护插入顺序(Map2和co.do,但是hashmaps没有),所以字符串可能会以不同的顺序列出元素。你插入它们。

答案 1 :(得分:8)

这个问题已经得到了解答,但我想指出,如果你想要的话,有更简单的方法可以产生这些字符串。像这样:

scala> val l = List("te", "st", "ing", "123")
l: List[java.lang.String] = List(te, st, ing, 123)

scala> l.mkString
res0: String = testing123

scala> val m = Map(1 -> "abc", 2 -> "def", 3 -> "ghi")
m: scala.collection.immutable.Map[Int,java.lang.String] = Map((1,abc), (2,def), (3,ghi))

scala> m.values.mkString
res1: String = abcdefghi