40

How do you use Map.foldLeft? According to the docs it looks like

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

But I'm having difficulty:

Map("first"->1,"second"->2).foldLeft(0)((a,(k,v)) => a+v )

error: not a legal formal parameter

The error points to the open bracket in front of k.

Eugene Yokota
  • 94,654
  • 45
  • 215
  • 319
Pengin
  • 4,692
  • 6
  • 36
  • 62

4 Answers4

93

If you want to use the (a, (k, v)) syntax, you need to advise the compiler to use pattern matching.

Map("first"->1, "second"->2).foldLeft(0){ case (a, (k, v)) => a+v }

Note that a case statement requires curly braces.

Debilski
  • 66,976
  • 12
  • 110
  • 133
  • 2
    Why is pattern matching required? Are there any other patterns which can be matched for in a foldLeft ? – ron_ron May 26 '20 at 05:02
19

I think, you can't do the pattern match on tuples as you expect:

Map("first"->1,"second"->2).foldLeft(0)((a, t) => a + t._2)

Actually, using values and sum is simpler.

Map("first"->1,"second"->2).values.sum
Thomas Jung
  • 32,428
  • 9
  • 84
  • 114
  • 6
    He _can_ pattern match on tuples. To pattern match, though, one needs to use `case`. – Daniel C. Sobral Nov 14 '10 at 21:28
  • @Daniel That's the advantage of my lawyer-like sentence: it's correct (he cannot pattern-match as he expected) but I've forgotten the case syntax. – Thomas Jung Nov 15 '10 at 08:56
  • 1
    For problems like this though, using `values` or `mapValues` is absolutely the clearest solution (which will almost always make it the right choice) – Kevin Wright Nov 15 '10 at 09:22
8

The trick is to use a partial function as the code block, in other words you add a case statement that matches on the arguments:

Map("first" -> 1, "second" -> 2).foldLeft(0) { case (a, (k, v)) => a + v }
Theo
  • 131,503
  • 21
  • 160
  • 205
  • Thank you sooo much Theo! This is what I've been looking for a while...but how can `case` be used without `match` keyword and how come is it being used as destructing action? – NikolaS May 30 '22 at 15:18
5

This is not really an answer to your question but I found it useful when starting out with folds, so I'll say it anyway! Note that the /: method "alias" for foldLeft can be clearer for two reasons:

xs.foldLeft(y) { (yy, x) => /* ... */ }

(y /: xs) { (yy, x) => /* ... */ }

Note that in the second line:

  • it's more clear that the value y is being folded into the collection xs
  • you can easily remember the ordering of the Tuple2 argument is the same as the ordering of the method "call"
oxbow_lakes
  • 133,303
  • 56
  • 317
  • 449