2013-03-01 2 views
8

以下は機能しません。セットによるスカラパターンマッチング

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") 
    } 
} 

error: not found: type xs

どのようにすることができますセット以上のIパターンマッチ?

答えて

15

まあ、x:xsタイプxsxを意味し、それは動作しません。しかし、悲しいかな、セットには定義された順序がないので、マッチセットをパターン化することはできません。または、もっと実用的には、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) 
+3

ニース。 Setには定義された順序がないので、SetExtractorを実際の値で使うべきではありません。 'case SetExtractor(1、xs @ _ *)=> ...'; 'Set(1,2,3)'で動作しますが、一般的には動作しません。 'Set(1,2,3,4,5)'で置き換えます。ダニエルは、解体バインドがSetから任意の要素を選ぶことを可能にする方法としてこれを提供しています。また、残りのxsはArrayBufferであることに注意してください。セットとして使うには 'xs.toSet'を使います。 – AmigoNico

4

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

here見られるように、そのパターンマッチングがSetのために非常に好ましくないと思われます。おそらく、明示的Listまたは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") 
    } 
} 
+0

そこにはまた、物事をbacktickedされますそれは価値にもマッチします。 –

+0

'Set'を' List'に変換するために遅れがありますか? –

+0

はい。パフォーマンス目的でパゴダのソリューションを使用することができます。パターンマッチングでどのように行うのかをお見せしたいと思っています。ところで、私の例では、 '_'ケースは決して – Danyel

5

SetからSetcase classないとunapply方法を持っていない変換する必要があります。

これらの2つのことは、Setで直接パターンマッチングできないことを意味します。
更新:ダニエルは正しく彼の答えに示したとおりに、Setのためにあなた自身の抽出を定義しない限り)あなたは、代替を見つける必要があります

、私は折り機能

def union(s: Set[Int], t: Set[Int]): Set[Int] = 
    (s foldLeft t) {case (t: Set[Int], x: Int) => t + x} 
を使用してお勧めしたいです

これはそれらを一


ずつ添加、 tsの要素を蓄積します

ここ

折りたたみ参考のために必要であれば、折り畳み操作のための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. 
+0

に届きません。そのため、' Set'クラスに 'unappy()'メソッドがない場合、マッチで分解することはできません。 –

+1

'unapply(...)'メソッドを持つオブジェクトは、* extractor *と呼ばれ、その目的は 'match/case'ブロックでパラメータを抽出する方法を定義することです。これは 'caseクラス'のために自動的に来ます。可能であれば、 "Programming in Scala 2nd ed。"の* ch.26 *を参照してください。参考のため。 –

1

これは、私が思い付くことができるものである。

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") 
} 
+0

も参照してください:[スタイルのコーディング:トレンチのスカラをする方法](http://parleys.com/play/52a11b33e4b039ad2298ca78/chapter58/about)0:39:45 –

関連する問題