コレクションをゼロから作成するトップビューイテレータ目次

イテレータ

イテレータはコレクションではなく、コレクションの要素に1つずつアクセスする方法です。 イテレータit上の基本的な演算にはnextおよびhasNextの2つがあります。 it.next()を呼ぶとイテレータの次の要素を返し、イテレータの状態を1つ進めます。 同じイテレータに対してもう一度nextを呼ぶと以前返ってきた要素よりも1つ先の要素が得られます。 もしそれ以上返す要素が無ければ、nextの呼び出しはNoSuchElementExceptionを投げます。 IteratorhasNextメソッドを使うとそれ以上返す要素があるかどうかわかります。

イテレータitの全ての要素を「進んでいく」最も率直な方法ではwhileループを使うものです:

while (it.hasNext) 
  println(it.next())

ScalaのイテレータはTraversable, IterableおよびSeqクラスにあるほとんどのメソッドに似たメソッドを提供します。 例えば、イテレータが返す各要素に対して与えられた手続きを実行するforeachメソッドを提供します。 foreachを使うと上記のループは次のように略せます:

it foreach println

いつもの通り、foreach, map, withFilter, およびflatMapを使う式の代わりにfor式も利用できるため、イテレータから返される全ての要素を表示するさらに別の方法は次のようになるでしょう:

for (elem <- it) println(elem)

イテレータのforeachメソッドとトラバーサブルコレクションの同じメソッドには重要な違いがあります: イテレータに対して呼ばれた場合、foreachは終了時にイテレータをその終わりの状態にします。 そのためもう一度nextメソッドを同じイテレータに対して呼ぶと、イテレータはNoSuchElementExceptionで失敗します。 対照的に、コレクションに対して呼ばれた場合、foreachはコレクション内の要素数を変えません(渡した関数が要素を追加または削除しない限り。ただ、追加や削除は驚くような結果を引き起こす場合があるので、推奨されません)。

IteratorTraversableと共通に持つ他の演算も同じ特性を持ちます。 例えば、イテレータは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は最後まで進んでいます(訳注: 実際にはmapを呼んだ時点ではなく、foreachを呼んだ時点。他のメソッドも同様に遅延的に評価する)。

別の例はイテレータの要素からある特性を持つ最初の要素を見付けるのに使えるdropWhileメソッドです。 例えば上記のイテレータ内から2文字以上の最初の単語を見付けるには次のように書けるでしょう:

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が変化した点に注意してください: イテレータは今リスト内の2番目の単語“number”を指しています(訳注: dropWhileも遅延的に評価するので、dropWhileを呼び出した時点ではまだitは変化しない。ただし、REPLはイテレータが空かどうか調べるためにhasNextを呼び出す。この時点でフィルタが動く。さらに言うとdropWhileバッファ付きイテレータを使って1要素先読みする。Iterator(...)で返ってくるイテレータのバッファ付きイテレータは先読みしても元となるイテレータを進めないが、他のイテレータのバッファ付きイテレータでは1つ先に進める可能性があるため、上記の例でit.next()"of"を返す可能性がある。上の例はあくまで性質を示すための例であり、正しい使い方としてはdropWhileが返したイテレータのみを使うようにし、元のイテレータにはさわらないようにする)。 さらに言えばdropWhileの結果res4itは全く同じ要素の列を返します。

同じイテレータを再利用できるようにする標準的な演算は1つだけあります:

val (it1, it2) = it.duplicate

の呼び出しによりイテレータitと全く同じ要素を返すイテレータが2つ得られます。 2つは独立に動作します。1つを進めてももう1つには影響しません。 対照的に、元のイテレータitduplicateにより最後まで進められており、そのため再利用できなくされています(訳注: これも遅延的に評価する)。

要約すると、イテレータはもしイテレータのメソッドを呼び出した後に再びアクセスしなければコレクションのように振舞います。 ScalaコレクションライブラリはこれをTraversableIteratorと共通の親クラスである抽象概念TraversableOnceとして明示化しています。 名前が示すように、TraversableOnceforeachメソッドを使って辿れますが、辿った後のそのオブジェクトの状態は指定されていません。 もしTraversableOnceが実はIteratorであれば、辿った後は最後に行きますが、Traversableであれば、元のままです。 TraversableOnceはイテレータかトラバーサブルのどちらかを取る引数の型としてよく使われます。 Traversableクラスの++メソッドはその例です。 ++メソッドは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) まずitの全ての要素を返し、その後全体で長さlen要素を返すまでxのコピーを返すイテレータ。
写像:
it map f itから返される全ての要素に関数fを適用して得られるイテレータ。
it flatMap f itから返される全ての要素にイテレータを値として返す関数fを適用し、結果を連結して得られるイテレータ。
it collect f itから返される全ての要素のうち部分関数fが定義されている物に対してfを適用し、結果を集めて得られるイテレータ。
変換:
it.toArray itから返される要素を配列に集める。
it.toList itから返される要素をリストに集める。
it.toIterable itから返される要素をイテラブルに集める。
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の別名)。 Test whether the collection contains elements (alias of hasNext).
it.size itによて返される要素数。注意: itはこの演算の後最後まで進む!
it.length it.sizeと同じ。
it.hasDefiniteSize itが有限個の要素を返すとわかっていれば真を返す(デフォルトではisEmptyと同じ)。
要素取得・添字検索:
it find p itよって返される要素で最初にpを満たすものを含むオプション値、 またはどの要素も適さなければNone。 注意: イテレータはその要素の後、またはもし見付からなければ最後へ進む。
it indexOf x itが返す要素で最初にxと等しいものの添字。 注意: イテレータはこの要素の後に進む。
it indexWhere p itが返す要素で最初にpを満たすものの添字。 注意: イテレータはこの要素の後に進む。
部分イテレータ:
it take n itの最初のn要素を返すイテレータ。 注意: itn番目の要素の後、またはもしn要素含んでいなければその最後に進む。
it drop n it(n+1)番目の要素から始まるイテレータ。 注意: itは同じ位置へ進む。
it slice (m,n) itが返す要素の、m番目の要素から始まりn番目の要素の前で終わるスライスを返すイテレータ。
it takeWhile p 条件pが真であるかぎりitの要素を返すイテレータ。
it dropWhile p 条件pが真であるかぎりitの要素を飛ばして、その残りを返すイテレータ。
it filter p itの要素で条件pを満たすものを全て返すイテレータ。
it withFilter p it filter pと同じ。イテレータがfor式で使えるようにするために必要。
it filterNot p itの要素で条件pを満たさないものを全て返すイテレータ。
分割:
it partition p itを2つのイテレータのペアに分割する。 1つはitの要素で述語pを満たす全ての要素を返し、 もう1つはitの要素で満たさない全ての要素を返す。
要素状態:
it forall p itによって返される全ての要素でpが成り立つか示す真偽値。
it exists p itによって返されるある要素でpが成り立つか示す真偽値。
it count p itによって返される要素でpを満たす要素数。
折り畳み:
(z /: it)(op) zから始まり左から右へ、二項演算opitが返す隣り合った要素に適用する。
(it :\ z)(op) zから始まり右から左へ、二項演算opitが返す隣り合った要素に適用する。
it.foldLeft(z)(op) (z /: it)(op)と同じ。
it.foldRight(z)(op) (it :\ z)(op)と同じ。
it reduceLeft op 左から右へ、二項演算opを空でないイテレータitが返す隣り合った要素に適用する。
it reduceRight op 右から左へ、二項演算opを空でないイテレータitが返す隣り合った要素に適用する。
特定の折り畳み:
it.sum イテレータitが返す数値要素値の和。
it.product イテレータitが返す数値要素値の積。
it.min イテレータitが返す順序付けされた要素値の最小値。
it.max イテレータitが返す順序付けされた要素値の最大値。
ジッパー:
it zip jt itjtが返す対応する要素のペアのイテレータ。
it zipAll (jt, x, y) itjtが返す対応する要素のペアのイテレータで、 短かいイテレータはxまたはyを追加して長い方に合うように拡張される。
it.zipWithIndex itにより返される要素とその添字のペアのイテレータ。
更新:
it patch (i, jt, r) itiから始まるr要素をパッチイテレータjtで置き替えてできるイテレータ。
比較:
it sameElements jt イテレータitjtが同じ要素を同じ順で返すか調べるテスト。 注意: itjtの少なくとも1つはこの演算の後に最後に進む。
文字列:
it addString (b, start, sep, end) itによって返される全ての要素をセパレータsepで区切って表示し、文字列startendで囲った文字列をStringBuilderに追加する。 start, sep, endは全て省略可能。
it mkString (start, sep, end) コレクションを、itによって返される全ての要素をセパレータsepで区切って表示し、文字列startendで囲った文字列に変換する。 start, sep, endは全て省略可能。

続いては:


コレクションをゼロから作成するトップビューイテレータ目次