イテレータ | 目次 |
最新版は Scala Documentation に移行しました。
イテレータ (Iterator) はコレクションではなく、コレクションから要素を一つづつアクセスするための方法だ。イテレータ it に対する基本的な演算として next と hasNext の二つがある。 it.next() を呼び出すことで、次の要素が返り、イテレータの内部状態が前進する。よって、同じイテレータに対して next を再び呼び出すと、前回返したものの次の要素が得られる。返す要素が無くなると、next の呼び出しは NoSuchElementException を発生させる。返す要素が残っているかは Iterator の hasNext メソッドを使って調べることができる。
イテレータ it が返す全ての要素を渡り歩くのに最も率直な方法は while ループを使うことだ:
while (it.hasNext) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
println(it.next()) |
Traversable、Iterable、および Seq クラスのほとんどのメソッドに対して類似するものを Scala のイテレータは提供している。たとえば、与えられた手順をイテレータが返す全ての要素に対して実行する foreach メソッドを提供する。foreach を使うことで、先ほどのループは以下のように短縮できる:
it foreach println |
例にならって、foreach、map、withFilter、および flatMap の代替構文として for 式を使うことができるので、イテレータが返す全ての要素を表示するもう一つの方法として以下のように書ける:
for (elem <- it) println(elem) |
イテレータの foreach メソッドと traversable の同メソッドには重大な違いがある。イテレータのそれを呼び出した場合、foreach はイテレータを終端に置いたままで終了するということだ。そのため、next を再び呼び出すと NoSuchElementException を発生して失敗する。それに比べ、コレクションに対して呼び出した場合、foreach はコレクション内の要素の数を変更しない (渡された関数が要素を追加もしくは削除した場合は別の話だが、これは予想外の結果になることがあるので非推奨だ)。
Iterator と Traversable に共通の他の演算も同じ特性を持つ。例えば、イテレータは新たなイテレータを返す map メソッドを提供する:
scala> val it = Iterator("a", "number", "of", "words") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
it: Iterator[java.lang.String] = non-empty iterator | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
scala> it.map(_.length) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res1: Iterator[Int] = non-empty iterator | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
scala> res1 foreach println | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
6 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
scala> it.next() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
java.util.NoSuchElementException: next on empty iterator |
上記の通り、it.map の呼び出しの後、イテレータ it は終端まで前進してしまっている。
次の具体例は、ある特性をもつイテレータ内の最初の要素を検索するのに使うことができる dropWhile だ。例えば、イテレータ内で二文字以上の最初の語句を検索するのに、このように書くことができる:
scala> val it = Iterator("a", "number", "of", "words") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
it: Iterator[java.lang.String] = non-empty iterator | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
scala> it dropWhile (_.length < 2) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res4: Iterator[java.lang.String] = non-empty iterator | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
scala> it.next() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res5: java.lang.String = number |
dropWhile を呼び出すことで it が変更された事に注意してほしい。イテレータは二番目の語句「number」を指している。実際に、it と dropWhile の返した戻り値である res4 同じ要素の列を返す。
同じイテレータを再利用するための標準演算が一つだけある。以下の
val (it1, it2) = it.duplicate |
への呼び出しはイテレータ it と全く同じ要素を返すイテレータを二つ返す。この二つのイテレータは独立して作動するため、片方を前進しても他方は影響を受けない。一方、元のイテレータ it は duplicate により終端まで前進したため、使いものにならない。
要約すると、イテレータはメソッドを呼び出した後、絶対にアクセスしなければコレクションのように振る舞う。Scala コレクションライブラリは、 Traversable と Iterator に共通の親クラスである TraversableOnce を提供することで、明示的にこれを示す。名前が示す通り、 TraversableOnce は foreach を用いて一度だけ探索することができるが、探索後のそのオブジェクトの状態は指定されていない。 TraversableOnce オブジェクトが Iterator ならば、探索後はその終端にあるし、もし Traversable ならば、そのオブジェクトは今まで通り存在する。 TraversableOnce のよく使われる事例としては、イテレータか Traversable を受け取ることができるメソッドの引数の型だ。その例として、 Traversable クラスの追加メソッド ++ がある。TraversableOnce パラメータを受け取るため、イテレータか Traversable なコレクションの要素を追加することができる。
イテレータの全演算は次の表にまとめられている。
Iterator トレイトの演算 | ||
---|---|---|
使用例 | 振る舞い | |
抽象メソッド: | ||
it.next() | イテレータの次の要素を返し、前進させる。 | |
it.hasNext | it が次の要素を返せる場合、true を返す。 | |
他のイテレータ: | ||
it.buffered | it が返す全ての要素を返すバッファ付きイテレータ。 | |
it grouped size |
it が返す要素を固定サイズの「かたまり」にして返すイテレータ。 | |
xs sliding size | it が返す要素を固定サイズの「窓」をスライドさせて返すイテレータ。 | |
複製: | ||
it.duplicate | it が返す全ての要素を独立して返すイテレータのペア。 | |
加算: | ||
it ++ jt | イテレータ it が返す全ての要素に続いてイテレータ jt の全ての要素を返すイテレータ。 | |
it padTo (len, x) | 全体で len個の要素が返るように、イテレータ it の全ての要素に続いて x を返すイテレータ。 | |
map 演算: | ||
it map f | it が返す全ての要素に関数 f を適用することによって得られるイテレータ。 | |
it flatMap f | it が返す全ての要素に対してイテレータ値を返す関数 f を適用し、その結果を連結したイテレータ。 | |
it collect f | it が返す全ての要素に対して部分関数 f が定義されている場合のみ適応し、その結果を集めたイテレータ。 | |
変換演算: | ||
it.toArray | it が返す要素を配列に集める。 | |
it.toList | it が返す要素をリストに集める。 | |
it.toIterable | it が返す要素を iterable に集める。 | |
it.toSeq | it が返す要素を列に集める。 | |
it.toIndexedSeq | it が返す要素を添字付き列に集める。 | |
it.toStream | it が返す要素をストリームに集める。 | |
it.toSet | it が返す要素を集合に集める。 | |
it.toMap | it が返すキー/値ペアをマップに集める。 | |
コピー演算: | ||
it copyToBuffer buf | it が返す要素をバッファ buf にコピーする。 | |
it copyToArray(arr, s, n) | it が返す最大 n 個の要素を配列 arr の添字 s より始まる位置にコピーする。最後の2つの引数は省略可能だ。 | |
サイズ演算: | ||
it.isEmpty | イテレータが空であるかどうかを調べる (hasNext の逆)。 | |
it.nonEmpty | イテレータに要素が含まれているかを調べる (hasNext の別名)。 | |
it.size | it が返す要素の数。注意: この演算の後、it は終端まで前進する! | |
it.length | it.size に同じ。 | |
it.hasDefiniteSize | it が有限数の要素を返すことが明らかな場合 true を返す (デフォルトでは isEmpty に同じ)。 | |
要素取得演算・添字検索演算: | ||
it find p | it が返す要素の中で条件関数 p を満たす最初の要素のオプション値、または条件を満たす要素が無い場合 None。注意: イテレータは探しだされた要素の次の要素、それが無い場合は終端まで前進する。 | |
it indexOf x | it が返す要素の中で x と等しい最初の要素の添字。注意: イテレータはこの要素の次の位置まで前進する。 | |
it indexWhere p | it が返す要素の中で条件関数 p を満たす最初の要素の添字、注意: イテレータはこの要素の次の位置まで前進する。 | |
部分イテレータ演算: | ||
it take n | it が返す最初の n個の要素を返すイテレータ。注意: it は、n個目の要素の次の位置、またはn個以下の要素を含む場合は終端まで前進する。 | |
it drop n | it の (n+1)番目の要素から始まるイテレータ。注意: it も同じ位置まで前進する。 | |
it slice (m,n) | it が返す要素の内、m番目から始まり n番目の一つ前で終わる切片を返すイテレータ。 | |
it takeWhile p | it が返す要素を最初から次々とみて、条件関数 p を満たす限り返していったイテレータ。 | |
it dropWhile p | it が返す要素を最初から次々とみて、条件関数 p を満たす限り飛ばしていき、残りを返すイテレータ。 | |
it filter p | it が返すの要素で条件関数 p を満たすものを返すイテレータ。 | |
it withFilter p | it filter p に同じ。イテレータが for 式で使えるように用意されている。 | |
it filterNot p | it が返すの要素で条件関数 p を満たさないものを返すイテレータ。 | |
分割演算: | ||
it partition p | it を二つのイテレータから成るペアに分割する。片方のイテレータは it が返す要素のうち条件関数 p を満たすものを返し、もう一方は it が返す要素のうち p を満たさないものを返す。 | |
要素条件演算: | ||
it forall p | it が返す全ての要素に条件関数 p が当てはまるかを示す boolean 値。 | |
it exists p | it が返す要素の中に条件関数 p を満たすものがあるかどうかを示す boolean 値。 | |
it count p | it が返す要素の中にで条件関数 p 満たすものの数。 | |
fold 演算: | ||
(z /: it)(op) | z から始めて、左から右へと it が返す隣接する要素に二項演算 op を次々と適用したもの。 | |
(it :\ z)(op) | z から始めて、右から左へと it が返す隣接する要素に二項演算 op を次々と適用したもの。 | |
it.foldLeft(z)(op) | (z /: it)(op) に同じ。 | |
it.foldRight(z)(op) | (it :\ z)(op) に同じ。 | |
it reduceLeft op | 左から右へと、空ではないイテレータ it が返す隣接する要素に二項演算 op を次々と適用したもの。 | |
it reduceRight op | 右から左へと、空ではないイテレータ it が返す隣接する要素に二項演算 op を次々と適用したもの。 | |
特定 fold 演算: | ||
it.sum | イテレータ it が返すの数値要素の値の和。 | |
it.product | イテレータ it が返すの数値要素の値の積。 | |
it.min | イテレータ it が返す順序付けされたの値の最小値。 | |
it.max | イテレータ it が返す順序付けされたの値の最大値。 | |
zip 演算: | ||
it zip jt | イテレータ it と jt が返す要素から対応したものペアにして返すイテレータ。 | |
it zipAll (jt, x, y) | イテレータ it と jt が返す要素から対応したものペアにして返すイテレータで、もし片方が短い場合は x か y を使って長いほうに合わせる。 | |
it.zipWithIndex | it が返す要素とその添字をペアにしたイテレータ。 | |
更新演算: | ||
it patch (i, jt, r) | it の、i から始まる r個の要素をパッチイテレータ ji が返す要素に置換したイテレータ。 | |
比較演算: | ||
it sameElements jt | イテレータ it と jt が同じ要素を同じ順序で返すかを調べる。注意: この演算の後、it の jt 少なくともどちらか一方は終端まで前進している。 | |
文字列演算: | ||
it addString (b, start, sep, end) | it が返す要素を sep で区切った後、start と end で挟んだ文字列を StringBuilder b に追加する。 start, sep, end は全て省略可能。 | |
it mkString (start, sep, end) | it が返す要素を sep で区切った後、start と end で挟んだ文字列に変換する。 start, sep, end は全て省略可能。 |
続いては、
イテレータ | 目次 |