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
Ответы
Ответ 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
))