6

次のように、同じ値がすべての場所に存在する場合にのみ一致するように、1 つのパターン内で単一の変数を複数回使用できるようにしたいと考えています。

list match {
  case x :: x :: xs => // recurse
}

一致しますが、一致List(1,1,2)しませんList(1,2,1)。しかし、これは でコンパイルできませんerror: x is already defined as value x

この質問を調査したところ、case 句にガードを含めることもできることがわかりました。

list match {
  case x1 :: x2 :: xs if x1==x2 => // recurse
}

これは同じように機能するようです(そうですよね?)。これは良いことですが、多くの場所で同じ値が必要な場合は、きれいに見えません。

list match {
  case x1::x2::x3::x4::xs if x1==x2 && x2==x3 && x3==x4 => // recurse
}

これを行うことができるよりエレガントな方法はありますか?


いくつかのメモ: はい、私はちょうど scala を学んでいます。その点で、私は完全に異なる解決策、または何かを実際に探しているわけではありませんが、特にパターン マッチングに関心があります。takeWhilefilter

4

3 に答える 3

8

Scalaは、その一致に関してそれほど柔軟性を提供していません(意図しない変数の再利用から生じるエラーに注意する必要があるため、これは良いことかもしれません)。

同一のアイテムが多数ある場合は、ネストされた一致を検討することをお勧めします(ただし、内側の一致が失敗して後で外側の一致が完了することはないため、すべてをローカルで処理する必要があります)。

list match {
  case x :: rest => rest match {
    case `x` :: `x` :: `x` :: xs => println("Four of the same")
    case _ => println("Well, nonempty at least")
  }
  case _ => println("Boring, there's nothing here!")
}

「この変数はすでにあります。チェックしてください。設定しないでください」という意味のバッククォートに注意してください。

または、繰り返し使用する特殊な機能がある場合は、カスタムマッチャーを作成できます。

object FourOf {
  def unapplySeq(xs: List[Int]): Option[(Int, List[Int])] = xs match {
    case x :: y :: z :: a :: rest if x==y && y==z && z==a => Some((x,rest))
    case _ => None
  }
}

そして、その複雑なパターンが必要なときはいつでもそれを使用してください:

list match {
  case FourOf(x,rest) => println("four of the same")
  case x :: more => println("Nonempty")
  case _ => println("Yawn")
}

これらはどちらも、明らかに期待していたものほど整然としていて柔軟性がありませんが、matchステートメントで同じ変数を割り当てることとテストすることを切り替えることが、とにかく明確なコードを書くための良い方法かどうかはわかりません。

于 2012-12-20T00:41:33.447 に答える
5

多くの繰り返しでは、(値を取得する代わりに)安定した識別子を使用して比較を行う場合があります。

val x = list.head 
list match {
  case `x`::`x`::`x`::`x`::xs => ....
}

ただし、これは空のリストでは機能しないことに注意してください(頭を取得することはできません)。

于 2012-12-20T00:41:42.970 に答える
3

レックスの答えは素晴らしいと思います。私はのファンですunapplySeq。しかし、あなたの主な悩みが==各ガードの'のシーケンスだけである場合、これはそれほど賢くなく、おそらく無駄な代替手段です。したがって、TMTOWTDIの精神では:

def same[A](xs: A*) = xs forall (xs.head==)

// Then in your pattern match,

list match {
  // case x1::x2::x3::x4::xs if x1==x2 && x2==x3 && x3==x4 => // recurse
  case x1::x2::x3::x4::xs if same(x1,x2,x3,x4) => // recurse
}

私はオムの答えも好きなので、ここに適応があります:

 list.headOption map (x => list match { 
   case `x`::`x`::`x`::`x`::xs => //...; 
   case _ => // ... 
 }) getOrElse {
   // do what you'd have done for an empty list...
 }
于 2012-12-20T03:57:53.607 に答える