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

Von*_*onn 11 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
Run Code Online (Sandbox Code Playgroud)

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

sep*_*p2k 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
Run Code Online (Sandbox Code Playgroud)

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

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

简而言之:第一个foldLeft说明起始值acc应该是什么的论点.

正如Tom指出的那样,你应该记住,map不一定保持插入顺序(Map2和co.do,但是hashmaps没有),所以字符串可能会以不同于你插入的顺序列出元素他们.

  • 您应该注意的一点是,地图不一定具有已定义的顺序,因此将其折叠为字符串会强制执行可能是任意的顺序.只是一个需要注意的警告. (2认同)

Dan*_*ral 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
Run Code Online (Sandbox Code Playgroud)