我想了解foldLeft
是如何为"地图"工作的。如果我有一个List并调用它foldLeft,其中包含一个零元素和一个函数,我确实理解它是如何工作的:
val list1 = List(1,2,3)
list1.foldLeft(0)((a,b) => a + b)
其中,我将零元素0
与list1
的第一个元素相加,然后再添加list1
的第二个元素,依此类推。因此,输出成为新的输入,第一个输入就是零元素。
现在我得到了代码
val map1 = Map(1 -> 2.0, 3 -> 4.0, 5 -> 6.2) withDefaultValue 0.0
val map2 = Map(0 -> 3.0, 3 -> 7.0) withDefaultValue 0.0
def myfct(terms: Map[Int, Double], term: (Int, Double)): Map[Int, Double] = ???
map1.foldLeft(map2)(myfct)
- 所以我这里的第一个元素是
Tuple2
,但由于map2
是Map
而不是Tuple2
,零元素是什么 - 当我们有一个
List
,即list1
时,我们总是"取list1
中的下一个元素"。map1
中的"下一个元素"是什么?是另一对map1
吗
在这种情况下,您可以将Map
视为元组列表。您可以创建这样的列表:List(1 -> 2.0, 3 -> 4.0, 5 -> 6.2)
,并在其上调用foldLeft
(这或多或少正是Map.foldLeft
的作用)。如果您了解foldLeft
如何处理列表,那么现在您也知道它如何处理"地图"了:)回答您的具体问题:
-
CCD_ 19的第一个参数可以是任何类型的。您也可以传入
Map
,而不是第一个示例中的Int
。它不必像您在第一个示例中那样与正在处理的集合的元素具有相同的类型(尽管它可能是),也不必像上一个示例中一样与集合本身具有相同类型。举个例子:List(1,2,3,4,5,6).foldLeft(Map.empty[String,Int]) { case(map,elem) => map + (elem.toString -> elem) }
这产生了与list.map { x => x.toString -> x }.toMap
相同的结果。正如您所看到的,这里的第一个参数是Map
,既不是List
也不是Int
。
传递给foldLeft
的类型也是它返回的类型,也是传递函数返回的类型。它不是";元素零";。foldLeft
将把该参数和列表的第一个元素一起传递给reducer函数。函数将组合这两个元素,并生成与第一个参数类型相同的新值。该值再次传入,再次与第二个元素一起传入。。。等也许,检查foldLeft
的签名会有所帮助:
foldLeft[B](z: B)(op: (B, A) ⇒ B): B
这里A
是集合元素的类型,B
可以是任何类型,唯一的要求是它出现的四个位置具有相同的类型。
这里是另一个例子,它(几乎)等同于list.mkString(",")
:
List(1,2,3,4,5,6).foldLeft("") {
case("", i) => i.toString
case(s,i) => s + "," + i
}
正如我在开头所解释的,在这种情况下,地图是一种列表(更确切地说是一个序列)。就像";我们总是选择列表的下一个元素";当我们处理列表时;地图的下一个元素";在这种情况下。你自己说过,地图的元素是元组,所以这就是下一个元素的类型:
Map("one" -> 1, "two" -> 2, "three" -> 3) .foldLeft("") { case("", (key,value)) => key + "->" + value case(s, (key,value)) => s + ", " + key + "->" + value }
如上所述,foldLeft
操作的签名如下所示:
foldLeft[B](z: B)(op: (B, A) ⇒ B): B
运算的结果类型为B
。所以,这回答了你的第一个问题:
所以我在这里的第一个元素是Tuple2,但由于map2是Map而不是一个Tuple2,零元素是什么?
零元素是您想要从foldLeft
输出的任何元素。它可以是CCD_ 35或CCD_ 36,也可以是其他任何东西。
函数签名(即第二个参数)中的op
,是您希望对map1的每个元素进行操作的方式,它是(key,value)
对,或者另一种写入方式是key -> value
。
让我们试着通过更简单的操作来构建它并理解它。
val map1 = Map(1 -> 1.0, 4 -> 4.0, 5 -> 5.0) withDefaultValue 0.0
val map2 = Map(0 -> 0.0, 3 -> 3.0) withDefaultValue 0.0
// Here we're just making the output an Int
// So we just add the first element of the key-value pair.
def myOpInt(z: Int, term: (Int, Double)): Int = {
z + term._1
}
// adds all the first elements of the key-value pairs of map1 together
map1.foldLeft(0)(myOpInt) // ... output is 10
// same as above, but for map2 ...
map2.foldLeft(0)(myOpInt) // ... output is 3
现在,通过使用零元素(z
)作为现有映射,将其带入下一步。。。我们基本上将元素添加到我们正在使用的映射中作为CCD_ 41。
val map1 = Map(1 -> 1.0, 4 -> 4.0, 5 -> 5.0) withDefaultValue 0.0
val map2 = Map(0 -> 0.0, 3 -> 3.0) withDefaultValue 0.0
// Here z is a Map of Int -> Double
// We expect a pair of (Int, Double) as the terms to fold left with z
def myfct(z: Map[Int, Double], term: (Int, Double)): Map[Int, Double] = {
z + term
}
map1.foldLeft(map2)(myfct)
// output is Map(0 -> 0.0, 5 -> 5.0, 1 -> 1.0, 3 -> 3.0, 4 -> 4.0)
// i.e. same elements of both maps concatenated together, albeit out of order, since Maps don't guarantee order ...
当我们有一个列表,即list1时,我们总是";中的下一个元素list1";。什么是";map1中的下一个元素?这是另一对map1吗?
是的,它是map1
中的另一个键值对(k,v)
。