Разрешает ли Scala такой экстрактор? - PullRequest
5 голосов
/ 16 июля 2011

Допустим, у меня есть эта коллекция:

val a = Array(Array(1,2,3,4,5),Array(4,5),Array(5),Array(1,2,6,7,8))

Есть ли способ определить экстрактор, который будет работать следующим образом:

a.foreach(e => {
   e match {
      case Array( ending with 5 ) => 
      case _ =>
   }
})

Извините за псевдокод, но я не знаю, как это выразить. Есть ли способ сопоставить что-то, имея 5 в качестве последнего элемента? Что если бы я захотел сопоставить что-то, имеющее 1 в качестве первого элемента и 5 в качестве последнего? Может ли это работать для массивов различной длины (обратите внимание, что я специально выбрал разные длины для своих массивов в примере).

Спасибо!

Ответы [ 4 ]

11 голосов
/ 16 июля 2011

Да, вы можете:

object EndsWith {
  def unapply[A]( xs: Array[A] ) = 
    if( xs.nonEmpty ) Some( xs.last ) else None
}

На вашем примере:

val a = Array(Array(1,2,3,4,5),Array(4,5),Array(5),Array(1,2,6,7,8))

a foreach { 
  case e @ EndsWith(5) => println( e.mkString("(",",",")" ) )
  case _ =>
}

Печатается как положено (1,2,3,4,5), (4,5) и (5)

При таком же подходе вы можете написать экстрактор StartWith, а затем добавить метод для объединения их в новый экстрактор, соответствующий обоим условиям.

9 голосов
/ 16 июля 2011
a.foreach(e => {
   e match {
      case a: Array[Int] if a.last == 5 => 
      case _ =>
   }
})

Вы можете сделать что-то немного лучше для сопоставления с первыми элементами:

a.foreach(e => {
   e match {
      case Array(1, _*) => 
      case _ => 
   }
})

К сожалению, вещь @_* должна быть последним элементом в списке аргументов массива.Но вы можете сделать сопоставление до этого настолько сложным, насколько захотите.

scala> val Array(1, x @_*) = Array(1,2,3,4,5)
x: Seq[Int] = Vector(2, 3, 4, 5)

scala> val Array(1, b, 3, x @_*) = Array(1,2,3,4,5)
b: Int = 2
x: Seq[Int] = Vector(4, 5)
4 голосов
/ 16 июля 2011

Синтаксис case поддерживает if s, поэтому это будет работать:

a foreach {
  case a: Array[Int] if a.last == 5 =>
  case _ =>
}
1 голос
/ 16 июля 2011
a.foreach (ar => ar.last match {                    
  case 5 => println ("-> 5] " + ar.mkString ("~"))
  case _ => println ("   ?] " + ar.mkString (":")) }) 

Почему вы не сопоставляете непосредственно последний элемент?

-> 5] 1~2~3~4~5
-> 5] 4~5
-> 5] 5
   ?] 1:2:6:7:8
...