Scala - может ли лямбда-параметр соответствовать кортежу? - PullRequest
47 голосов
/ 23 августа 2011

Скажем, у меня есть список вроде

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

А потом я хочу отфильтровать одну из них, я могу сделать что-то вроде

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

Есть ли способ, которым я могу "распаковать" кортеж в качестве параметра непосредственно в лямбду, вместо этой промежуточной переменной item?

Что-то вроде следующего было бы идеально, но затмение говорит мне wrong number of parameters; expected=1

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

Буду признателен за любую помощь - используя 2.9.0.1

Ответы [ 5 ]

79 голосов
/ 23 августа 2011

Это самое близкое, что вы можете получить:

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

Это в основном синтаксис сопоставления с образцом внутри анонимной PartialFunction . Существуют также методы tupled в Function объектах и ​​признаках, но они являются просто оболочкой для этого выражения соответствия шаблону.

18 голосов
/ 24 августа 2011

Хм, хотя у Киптона хороший ответ.Вы можете на самом деле сделать это короче, сделав.

val l = List((1, "blue"), (5, "red"), (2, "green"))
val m = l.filter(_._1 != 2)
8 голосов
/ 23 августа 2011

Есть несколько вариантов:

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
5 голосов
/ 23 февраля 2015
val m = l.filter( (n, s) => n != 2 )

... несоответствие типов, потому что лямбда определяет

  • Function2[String,Int,Boolean] с двумя параметрами вместо
  • Function1[(String,Int),Boolean] с одним Tuple2[String,Int] в качестве параметра.

Вы можете конвертировать между ними так:

val m = l.filter( ((n, s) => n != 2).tupled )
0 голосов
/ 04 декабря 2014

Я размышлял над тем же и пришел к вашему вопросу сегодня.

Мне не очень нравятся подходы с частичными функциями (все, что имеет case), поскольку они подразумевают, что может быть больше точек входа для логического потока. По крайней мере, для меня они имеют тенденцию размывать намерения кода. С другой стороны, я действительно хочу идти прямо к кортежным полям, как вы.

Вот решение, которое я разработал сегодня. Кажется, это работает, но я еще не пробовал в производстве.

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

Выход:

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

Может быть, это окажется полезным. Естественно, объект unTuple следует оставить в некотором пространстве имен инструмента.

Добавление:

Применительно к вашему делу:

val m = l.filter( unTuple( (n:Int,color:String) =>
    n != 2
))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...