Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

flatMap on a map gives error: wrong number of parameters; expected = 1

Tags:

scala

I have a map m

val m = Map(1->2, 3->4, 5->6, 7->8, 4->4, 9->9, 10->12, 11->11)

Now i want a map whose keys are equal to the values. So i do this

def eq(k: Int, v: Int) = if (k == v) Some(k->v) else None
m.flatMap((k,v) => eq(k,v))

This gives me the error

error: wrong number of parameters; expected = 1
m.flatMap((k,v) => eq(k,v))

Whats wrong with the above code? flatMap expects a one argument function and here i am passing one argument which is a Pair of integers.

Also this works

m.flatMap {
   case (k,v) => eq(k,v)
}

but this does not

m.flatMap {
      (k,v) => eq(k,v)
}

Looks like i am missing something. Help?

like image 656
lovesh Avatar asked Apr 23 '14 16:04

lovesh


4 Answers

There is no such syntax:

m.flatMap((k,v) => eq(k,v))

Well, in fact there is such syntax, but actually it is used in functions that accept two arguments (like reduce):

List(1,2,3,4).reduce((acc, x) => acc + x)

The

m.flatMap {
   case (k,v) => eq(k,v)
}

syntax works because in fact it is something like this:

val temp: PartialFunction[Tuple2[X,Y], Tuple2[Y,X]] = { 
   case (k,v) => eq(k,v) // using literal expression to construct function
} 

m.flatMap(temp) // with braces ommited

They key thing here is the usage of case word (actually, there is a discussion to enable your very syntax) which turns usual braces expression, like { ... } into full blown anonymous partial function

like image 53
om-nom-nom Avatar answered Nov 19 '22 05:11

om-nom-nom


(If you want to simply fix the error you're getting, see the 2nd solution (with flatMap); if you want a generally nicer solution, read from the beginning.)

What you need instead is filter not flatMap:

def eq(k: Int, v: Int) = k == v

val m = Map(1->2, 3->4, 5->6, 7->8, 4->4, 9->9, 10->12, 11->11)

m.filter((eq _).tupled)

...which of course reduces to just the following, without the need for eq:

m.filter { case (k, v) => k == v }

result:

Map(9 -> 9, 11 -> 11, 4 -> 4)

OR... If you want to stick with flatMap

First you must know that flatMap will pass to your function TUPLES not keys and values as separate arguments.

Additionally, you must change the Option returned by eq to something that can be fed back to flatMap on sequences such as List or Map (actually any GenTraversableOnce to be precise):

def eq(k: Int, v: Int) = if (k == v) List(k -> v) else Nil

m.flatMap { case (k,v) => eq(k,v) } // use pattern matching to unpack the tuple

or the uglier but equivalent:

m.flatMap { x => eq(x._1, x._2) }

alternatively, you can convert eq to take a tuple instead:

m.flatMap((eq _).tupled)
like image 43
Erik Kaplun Avatar answered Nov 19 '22 05:11

Erik Kaplun


I think that what you want is a single argument that will be a couple, not two arguments. Something like this may work

m.flatMap(k => eq(k._1, k._2))

The code snippet that works uses pattern matching. You give names to both elements of your couple. It's a partial function and can be use here in your flatMap.

like image 3
Agemen Avatar answered Nov 19 '22 03:11

Agemen


You have to do:

m.flatMap { case (k,v) => eq(k,v) }

Note that here I switch to curly braces, which indicates a function block rather than parameters, and the function here is a case statement. This means that the function block I'm passing to flatMap is a partialFunction that is only invoked for items that match the case statement.

like image 3
Konstantin Yovkov Avatar answered Nov 19 '22 05:11

Konstantin Yovkov