Scala - can lambda parameter match tuple?

So to speak, I have a list, for example

val l = List((1, "blue"), (5, "red"), (2, "green")) 

And then I want to filter out one of them, I can do something like

 val m = l.filter(item => { val (n, s) = item // "unpack" the tuple here n != 2 } 

Is there any way to “unpack” a tuple as a parameter for lambda directly, instead of this intermediate variable item ?

Something like the following would be ideal, but eclipse tells me the wrong number of parameters; expected=1 wrong number of parameters; expected=1

 val m = l.filter( (n, s) => n != 2 ) 

Any help would be appreciated - using 2.9.0.1

+43
scala
Aug 23 '11 at 15:37
source share
5 answers

This is roughly what you can get:

  val m = l.filter { case (n, s) => n != 2 } 

Basically the pattern matching syntax is inside the anonymous PartialFunction . There are also tupled methods in the object and Function properties, but they are just a wrapper around this pattern matching.

+69
Aug 23 '11 at 15:43
source share

Hmm, although Kipton has a good answer. You can make it shorter by doing.

 val l = List((1, "blue"), (5, "red"), (2, "green")) val m = l.filter(_._1 != 2) 
+19
Aug 23 2018-11-21T00:
source share

There are several options:

 for (x <- l; (n,s) = x if (n != 2)) yield x l.collect{ case x @ (n,s) if (n != 2) => x } l.filter{ case (n,s) => n != 2 } l.unzip.zipped.map((n,s) => n != 2).zip // Complains that zip is deprecated 
+8
Aug 23 2018-11-21T00:
source share
 val m = l.filter( (n, s) => n != 2 ) 

... is a type mismatch because lambda defines

  • Function2[String,Int,Boolean] with two parameters instead
  • Function1[(String,Int),Boolean] with one Tuple2[String,Int] as its parameter.

You can convert between them as follows:

 val m = l.filter( ((n, s) => n != 2).tupled ) 
+4
Feb 23 '15 at 19:44
source share

I thought the same thing and came to you today.

I don't really like partial function approaches (anything having a case ), as they imply that there may be more entry points for the logical stream. At least for me they tend to blur the intention of the code. On the other hand, I really want to go straight to the fields of the tuple, for example, to you.

Here is the solution I developed today. This seems to work, but I haven't tried it in production yet.

 object unTuple { def apply[A, B, X](f: (A, B) => X): (Tuple2[A, B] => X) = { (t: Tuple2[A, B]) => f(t._1, t._2) } def apply[A, B, C, X](f: (A, B, C) => X): (Tuple3[A, B, C] => X) = { (t: Tuple3[A, B, C]) => f(t._1, t._2, t._3) } //... } val list = List( ("a",1), ("b",2) ) val list2 = List( ("a",1,true), ("b",2,false) ) list foreach unTuple( (k: String, v: Int) => println(k, v) ) list2 foreach unTuple( (k: String, v: Int, b: Boolean) => println(k, v, b) ) 

Output:

 (a,1) (b,2) (a,1,true) (b,2,false) 

It may be useful. The unTuple object unTuple naturally be set aside in some tool namespace.

Application:

Applicable to your case:

 val m = l.filter( unTuple( (n:Int,color:String) => n != 2 )) 
-one
Dec 04 '14 at 13:30
source share



All Articles