今回は条件付きFor文。
for文に条件を指定することで適用対象をフィルタすることができる。
val a = Array(1, 2, 3, 4); for (i: Int <- a if i % 2 == 0) print(i);実行結果は、
24この機能はこんな風にもかける。
val a = Array(1, 2, 3, 4); a.withFilter((i: Int) => i % 2 == 0).foreach(i => print(i))これだけを見ると、withFilter()でフィルタされたArrayが返ってきて、 それにforeachをしているように見えるがちょっと違う。
続けないでちゃんと書くと、
val a = Array(1, 2, 3, 4); val filtered : FilterMonadic[Int, Array[Int]] = a.withFilter((i: Int) => i % 2 == 0); filtered.foreach((i: Int) => print(i))こんな感じ。
実際に、a.withFilter() の結果として帰ってきているのは、
print (filtered.getClass());で見ると、scala.collection.TraversableLike$WithFilter であることがわかる。
ちなみに、TraversableLike$WithFilter#foreach の実装を見ると、
def foreach[U](f: A => U): Unit = for (x <- self) if (p(x)) f(x)となっている。
つまり、withFilter()で帰ってきているのはデータ(Array)とフィルタ条件を持ったObjectで、そのforeach()の中で条件付きfor文を実行しているということになる。
結論: 最初から、条件付きfor文を使えばいいじゃん。
foreach構文を使うためには対象のオブジェクトは
def foreach[U](f: A => U): Unit
メソッドを実装する必要があった。
foreach - if 構文を使うためには、
def withFilter(p: A => Boolean): FilterMonadic[A, Repr]
を実装する必要がある。
object ForIfSample { def main(args: Array[String]) { val array : Array[Int] = Array[Int](1,2); val fe = new ForEachIfable[Int, Array[Int]](array); for (i: Int <- fe if i % 2 == 0) print(i); } } class ForEachIfable[A, Repr <: Array[A] ](col: Repr) { self=>; def repr: Repr = col; def foreach[U](f: A => U): Unit = { println("Here is ForEachIfable#foreach"); for (x : A <- repr) print(x); } def withFilter(p: A => Boolean): FilterMonadic[A, Repr] = { println("Here is ForEachIfable#withFilter"); new WithFilter(p); } // 以下のWithFilterクラスはTraversable.WithFilterと同じ。 class WithFilter(p: A => Boolean) extends FilterMonadic[A, Repr] { def map[B, That](f: A => B) (implicit bf: CanBuildFrom[Repr, B, That]): That = { val b = bf(repr) for (x <- self) if (p(x)) b += f(x) b.result } def flatMap[B, That](f: A => GenTraversableOnce[B]) (implicit bf: CanBuildFrom[Repr, B, That]): That = { val b = bf(repr) for (x <- self) if (p(x)) b ++= f(x).seq b.result } def foreach[U](f: A => U): Unit= for (x : A <- self) if (p(x)) f(x) def withFilter(q: A => Boolean): WithFilter = new WithFilter(x => p(x) && q(x)) } }withFilter()が返すFilterMonadicの実装はTraversable.WithFilterクラスの実装をそのまま使っている。 そのため、ForEachIfableがやや無理やりになっている。
実行結果:
Here is ForEachIfable#withFilter Here is ForEachIfable#foreach 12確かに、ForEachIfable#foreach、withFilterが実行されていることがわかる。
0 件のコメント:
コメントを投稿