Функциональные литералы Scala и синтаксис заполнителей в заархивированных коллекциях

Я в настоящее время изучаю Scala и боролся с использованием синтаксиса заполнителя на zipколлекции пед. Например, я хочу отфильтровать заархивированный массив из элементов, где l2[i] >= l1[i]. Как я могу сделать это, используя явный литерал функции или синтаксис заполнителя? Я пытался:

scala> val l = List(3, 0, 5) zip List(1, 2, 3)
l: List[(Int, Int)] = List((3,1), (4,2), (5,3))

scala> l.filter((x, y) => x > y)
<console>:9: error: missing parameter type
Note: The expected type requires a one-argument function accepting a 2-Tuple.
      Consider a pattern matching anonymous function, `{ case (x, y) =>  ... }`
              l.filter((x, y) => x > y)
                        ^
<console>:9: error: missing parameter type
              l.filter((x, y) => x > y)

scala> l.filter((x:Int, y:Int) => x > y)
<console>:9: error: type mismatch;
     found   : (Int, Int) => Boolean
     required: ((Int, Int)) => Boolean
                  l.filter((x:Int, y:Int) => x > y)

Попробуем синтаксис заполнителя:

scala> l.filter(_ > _)
      <console>:9: error: missing parameter type for expanded function ((x$1, x$2) => x$1.$greater(x$2))
  Note: The expected type requires a one-argument function accepting a 2-Tuple.
  Consider a pattern matching anonymous function, `{ case (x$1, x$2) =>  ... }`
        l.filter(_ > _)
            ^
<console>:9: error: missing parameter type for expanded function ((x$1: <error>, x$2) => x$1.$greater(x$2))
        l.filter(_ > _)

Так что, кажется, требуется функция на Pair:

scala> l.filter(_._1 > _._2)
<console>:9: error: missing parameter type for expanded function ((x$1, x$2) => x$1._1.$greater(x$2._2))
Note: The expected type requires a one-argument function accepting a 2-Tuple.
      Consider a pattern matching anonymous function, `{ case (x$1, x$2) =>  ... }`
              l.filter(_._1 > _._2)
                       ^
<console>:9: error: missing parameter type for expanded function ((x$1: <error>, x$2) => x$1._1.$greater(x$2._2))
              l.filter(_._1 > _._2)

Так что я делаю не так? Является match кстати единственный? Спасибо за помощь.

2 ответа

Решение

Как вы узнали filter над List требуется функция только с одним параметром (в вашем случае Tupple2 ака "пара"):

def filter(p: (A) => Boolean): List[A]

И это (x, y) => x > y означает функцию с двумя параметрами (A, B) => Boolean, Таким образом, вы пошли в правильном направлении в использовании _1 а также _2, но каждое использование _ представляет новый параметр, так _._1 > _._2 на самом деле эквивалентно (x, y) => x._1 > y._2, Таким образом, если вы хотите использовать один и тот же аргумент более одного раза, вы не можете использовать подчеркивание:

l.filter(p => p._1 > p._2)

Другая возможность заключается в использовании сопоставления с образцом для расширения Tupple2:

l.filter{ case (x, y) => x > y }

Кроме того, вы можете использовать zipped который вернет Tuple2Zipped и его фильтр принимает функцию с двумя параметрами (упрощенная подпись ниже):

def filter(f: (El1, El2) => Boolean): (List[El1], List[El2])

Вы можете использовать zipped сюда:

scala> val l = (List(3, 0, 5), List(1, 2, 3)) zipped
l: scala.runtime.Tuple2Zipped[Int,List[Int],Int,List[Int]] = scala.runtime.Tuple2Zipped@8dd86903

scala> l.filter(_ > _)
res1: (List[Int], List[Int]) = (List(3, 5),List(1, 3))

scala> l.filter(_ > _).zipped.toList
res2: List[(Int, Int)] = List((3,1), (5,3))

filter из Tuple2Zipped возвращает пару списков вместо списка пар, поэтому для преобразования во вторую форму вы можете использовать .zipped.toList,

Использовать этот:

l.filter { case (x, y) => x > y }

или же

l.filter(x => x._1 > x._2)

Также в Scala информация о типах не передается от тела функции к ее аргументам.

Другие вопросы по тегам