Подтвердить что ты не робот

Scala - может ли параметр лямбда соответствовать кортежу?

Так сказать, у меня есть список, например

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?

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

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

Любая помощь была бы оценена - используя 2.9.0.1

4b9b3361

Ответ 1

Это примерно то, что вы можете получить:

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

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

Ответ 2

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

val l = List((1, "blue"), (5, "red"), (2, "green"))
val m = l.filter(_._1 != 2)

Ответ 3

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

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

Ответ 4

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

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

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

Вы можете конвертировать между ними следующим образом:

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

Ответ 5

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

Я не очень люблю подходы с частичной функцией (что-либо имеющее 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
))