web-dev-qa-db-ja.com

Scalaリスト以外のシーケンスのパターンマッチング

リスト内の各要素を再帰的に操作する次のコードがあります

def doMatch(list: List[Int]): Unit = list match {
  case last :: Nil  => println("Final element.")
  case head :: tail => println("Recursing..."); doMatch(tail)
}

現在、この機能がfilter()およびforeach()を介して利用可能であることを無視すると、これは問題なく機能します。ただし、Seq [Int]を受け入れるように変更しようとすると、問題が発生します。

  • Seqには::はありませんが、+:はあります。これは基本的に同じことです。ただし、head +:tailで一致させようとすると、コンパイラは「error:not found:value +:」と文句を言います。
  • NilはListに固有であり、何に置き換えるのかわかりません。前の問題を乗り越えたなら、Seq()を試してみる

動作しないことを除いて、コードは次のように見えるはずです。

def doMatch(seq: Seq[Int]): Unit = seq match {
  case last +: Seq() => println("Final element.")
  case head +: tail  => println("Recursing..."); doMatch(tail)
}

編集:たくさんの良い答え! ::は私の例では演算子ではなく、ケースクラスであり、したがって違いであると最初に述べたので、私はagilesteelの答えを受け入れます。

53
Zecrates

Scalaには2つの_::_(短所と発音)があります。 1つは_class List_で定義された演算子で、もう1つは classListのサブクラス)です。これは、先頭と末尾で特徴付けられる空でないリストを表します。

_head :: tail_は、::(head, tail)から構文的に変更されたコンストラクターパターンです。

_::_はケースクラスです。つまり、抽出オブジェクトが定義されています。

24
agilesteel

一種の不正行為ですが、ここにそれがあります:

def doMatch(seq: Seq[Int]): Unit = seq match {
  case Seq(x) => println("Final element " + x)
  case Seq(x, xs@_*) => println("Recursing..." + x); doMatch(xs)
}

理由を聞かないでくださいxs*は機能しません...

51
Landei

2012年3月の時点で、これは2.10以降で動作します。

  def doMatch(seq: Seq[Int]): Unit = seq match {
    case last +: Seq() => println("Final element.")
    case head +: tail  => println("Recursing..."); doMatch(tail)
  }                                               //> doMatch: (seq: Seq[Int])Unit

  doMatch(List(1, 2))                             //> Recursing...
                                                  //| Final element.

より一般的には、 SeqExtractorsSeqに、append/prependをミラーリングする2つの異なるhead/tailおよびinit/last分解オブジェクトが追加されました。

List(1, 2) match { case init :+ last => last } //> res0: Int = 2                                              
List(1, 2) match { case head +: tail => tail } //> res1: List[Int] = List(2)                                               
Vector(1, 2) match { case init :+ last => last } //> res2: Int = 2                                              
Vector(1, 2) match { case head +: tail => tail } //> res3: scala.collection.immutable.Vector[Int] = Vector(2)
49
yakshaver

実際に_+:_のオブジェクトを定義して、探していることを正確に行うことができます。

_object +: { 
  def unapply[T](s: Seq[T]) = 
    if(s.nonEmpty)
      Some(s.head, s.tail) 
    else
      None
}

scala> val h +: t = Seq(1,2,3)
h: Int = 1
t: Seq[Int] = List(2, 3)
_

その後、コードは期待どおりに機能します。

これは、h +: t_がパターンのマッチングに使用されたときに+:(h,t)と同等であるため機能します。

24
dhg

標準ライブラリには、任意のシーケンスに対するパターンマッチングのサポートはないと思います。ただし、パターンマッチングなしで実行できます。

  def doMatch(seq: Seq[Int]) {
    if (seq.size == 1) println("final element " + seq(0)) else {
      println("recursing")
      doMatch(seq.tail)
    }
  }
  doMatch(1 to 10)

ただし、独自の抽出オブジェクトを定義できます。 http://www.scala-lang.org/node/112 を参照してください

object SEQ {
  def unapply[A](s:Seq[A]):Option[(A, Seq[A])] = {
    if (s.size == 0) None else {
      Some((s.head, s.tail))
    }
  }
}

def doMatch(seq: Seq[Int]) {
  seq match {
    case SEQ(head, Seq()) => println("final")
    case SEQ(head, tail) => {
      println("recursing")
      doMatch(tail)
    }
  }
}
4
Kim Stebel