今回は条件付き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 件のコメント:
コメントを投稿