Java の foreach を使い倒す
ループというのはプログラムでもっとも重要な要素の一つであり、どのような構文をもつかでその言語の一つの顔ができるものだ。Ruby の times なんてわりと好きだが、関数型の fold, map, iter なんかもいい。Python の for も iterator ベースで、良く設計できている。Java にも foreach が出現して大変便利なんだがちょっと貧弱だよね、例えば iteri (ループしながら何周目かカウントしたい)しようとしたとたんに、昔の for を使ったり、ループの外で一つ変数を宣言するのはダサくね、とおもっていたが実はわりと簡単に回避できるのだ。
public class WithIndex<T> implements Iterable<Pair<Integer, T>> { Iterable<T> container; public WithIndex(Iterable<T> container) { this.container = container; } public static <S> WithIndex<S> make(Iterable<S> container) { return new WithIndex<S>(container); } public Iterator<Pair<Integer, T>> iterator() { final Iterator<T> it = container.iterator(); final int[] index = new int[1]; return new Iterator<Pair<Integer, T>>() { public boolean hasNext() { return it.hasNext(); } public Pair<Integer, T> next() { T next = it.next(); return new Pair<Integer, T>(index[0]++, next); } public void remove() { it.remove(); index[0]--; } }; } }
static の make 関数は、いわゆる make_pair 的イディオム。Pair というクラスが Java にないのがイケテない。自前で用意。こんな感じに使える。
for (Paire: WithIndex.make(v)) { System.out.println("" + e.getFirst() + ": " + e.getSecond()); }
分かると思うが、getFirst() でインデックスが返ってくる。v は Vector
こんな感じに応用すれば、コピーを作らずに zip(リストのペアをペアのリストに)ができたり、bigram に対して foreach したり、foreach でファイルアクセスできますよ。明日から楽しい iterable ライフを。