web-dev-qa-db-ja.com

Scalaセットとのパターンマッチング

以下は機能しません。

object Foo {
    def union(s: Set[Int], t: Set[Int]): Set[Int] = t match {
        case isEmpty => s
        case (x:xs)  => union(s + x, xs)
        case _       => throw new Error("bad input")
    }
}

エラー:見つかりません:タイプxs

セット全体でパターンマッチングを行うにはどうすればよいですか?

17
Kevin Meredith

上手、 x:xsはタイプxxsを意味するため、機能しません。ただし、残念ながら、セットには定義された順序がないため、マッチセットをパターン化することはできません。または、より実用的には、Setに抽出機能がないためです。

ただし、いつでも独自に定義できます。

object SetExtractor {
  def unapplySeq[T](s: Set[T]): Option[Seq[T]] = Some(s.toSeq)
}

例えば:

scala> Set(1, 2, 3) match {
     |   case SetExtractor(x, xs @ _*) => println(s"x: $x\nxs: $xs")
     | }
x: 1
xs: ArrayBuffer(2, 3)
19

Setcase classではなく、unapplyメソッドもありません。

これらの2つのことは、Setで直接パターンマッチングを行うことができないことを意味します。
updateSetに対して独自のextractorを定義しない限り、Danielは正しく彼の答えに示されています)

別の方法を見つける必要があります。折り畳み機能を使用することをお勧めします

def union(s: Set[Int], t: Set[Int]): Set[Int] = 
    (s foldLeft t) {case (t: Set[Int], x: Int) => t + x}

または、最も明示的な型注釈を回避する

def union(s: Set[Int], t: Set[Int]): Set[Int] =
  (s foldLeft t)( (union, element) => union + element )

またはさらに短い

def union(s: Set[Int], t: Set[Int]): Set[Int] =
  (s foldLeft t)(_ + _)

これにより、sの要素がtに蓄積され、1つずつ追加されます。


折りたたみ

参照が必要な場合は、折り畳み操作の docs を次に示します。

foldLeft[B](z: B)(op: (B, A) ⇒ B): B

二項演算子を開始値とこのセットのすべての要素に左から右に適用します。

注:基になるコレクションタイプが順序付けられていない限り、実行ごとに異なる結果が返される場合があります。または、演算子は結合法則と可換法則です。

B the result type of the binary operator.
z the start value.
op the binary operator.
returns the result of inserting op between consecutive elements of this set, going left to right with the start value z on the left:

op(...op(z, x_1), x_2, ..., x_n)
where x1, ..., xn are the elements of this set.
7
pagoda_5b

まず第一に、あなたのisEmptyは、このコンテキストでは変数であるため、すべてのSetをキャッチします。定数はScalaの大文字で始まり、この条件が当てはまる場合にのみ定数として扱われます。したがって、小文字は任意のSetisEmptyに割り当てます(あなたはEmptySetを探していますか?)

見られるように ここ 、パターンマッチングはSetsにはあまり好ましくないようです。おそらく、SetListまたはSeqtoList/toSeq)に明示的に変換する必要があります。

object Foo {
    def union(s: Set[Int], t: Set[Int]): Set[Int] = t.toList match {
        case Nil => s
        case (x::xs)  => union(s + x, xs.toSet)
        case _       => throw new Error("bad input")
    }
}
5
Danyel

これは私が思いつくことができるものです:

object Contains {
  class Unapplier[T](val t: T) {
    def unapply(s: Set[T]): Option[Boolean] = Some(s contains t)
  }
  def apply[T](t: T) = new Unapplier(t)
}

object SET {
  class Unapplier[T](val set: Set[T]) {
    def unapply(s: Set[T]): Option[Unit] = if (set == s) Some(Unit) else None
  }
  def apply[T](ts: T*) = new Unapplier(ts.toSet)
}

val Contains2 = Contains(2)
val SET123 = SET(1, 2, 3)

Set(1, 2, 3) match {
  case SET123()         => println("123")
  case Contains2(true)  => println("jippy")
  case Contains2(false) => println("ohh noo")
}
2
Peter Schmitz
    t match {
      case s if s.nonEmpty => // non-empty 
      case _ => // empty
    }
0