3

我很想了解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)
  1. 所以我这里的第一个元素是 a Tuple2,但既然map2是 aMap而不是 a Tuple2,那么零元素是什么?
  2. 当我们有 aListlist1,我们总是“取下一个元素list1”。什么是“下一个元素” map1?是另一对map1吗?
4

2 回答 2

7

在这种情况下,您可以将 aMap视为元组列表。您可以创建一个这样的列表:List(1 -> 2.0, 3 -> 4.0, 5 -> 6.2),并调用foldLeft它(这或多或少正是这样Map.foldLeft做的)。如果您了解foldLeft列表的工作原理,那么现在您也知道它如何与地图一起工作:) 回答您的具体问题:

  1. 的第一个参数foldLeft可以是任何类型。您也可以在第一个示例中传入 aMap而不是a 。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。如您所见,这里的第一个参数是 a Map,既不是List也不是a Int

你传入foldLeft的类型也是它返回的类型,也是你传入的函数返回的类型。它不是“零元素”。 foldLeft将该参数与列表的第一个元素一起传递给您的减速器函数。您的函数将组合这两个元素,并生成与第一个参数相同类型的新值。再次传入该值,再次使用第二个元素......等等。也许,检查签名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
   }
  1. 正如我在开头所解释的,在这种情况下,地图是一种列表(更确切地说是一个序列)。就像在处理列表时“我们总是取列表的下一个元素”一样,在这种情况下我们将取“地图的下一个元素”。你自己说过,地图的元素是元组,所以下一个元素的类型是这样的:

     Map("one" -> 1, "two" -> 2, "three" -> 3)
      .foldLeft("") { 
        case("", (key,value)) => key + "->" + value
        case(s, (key,value)) => s + ", " + key + "->" + value
      }
    
于 2016-05-06T11:01:58.117 回答
1

如上所述,foldLeft操作的签名如图所示:

foldLeft[B](z: B)(op: (B, A) ⇒ B): B

操作的结果类型是B。所以,这回答了你的第一个问题:

所以我这里的第一个元素是 Tuple2,但是由于 map2 是 Map 而不是 Tuple2,那么零元素是什么?

零元素是您想要从foldLeft. 它可以是一个Int或一个Map或任何其他的东西。

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元素z

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 ...

当我们有一个 List,即 list1 时,我们总是“取 list1 中的下一个元素”。“map1 中的下一个元素是什么?是另一对 map1 吗?”

是的,它(k,v)map1.

于 2021-09-30T22:04:06.733 回答