Kotlinのコレクション操作メソッドをCollectionでないクラスでも使う

Kotlinではコレクション操作メソッドが豊富で、ボイラープレートコードを排除したスマートなコーディングができて大変快適ですね。しかし、既存クラスの中にはコレクション的なクラスなのだが、Collectionでない、というかIterableでないクラスが存在します。Collectionだと思って`map`を使おうとしたら使えない！！ってなるあれです。

でもまあ、当然ですが、Kotlinだと拡張関数が使えるので、拡張関数で`forEach`とか定義すれば同じ書き方ができます。
KTXで提供されているViewGroupに対する`forEach`みたいなものですね。

```kotlin
inline fun ViewGroup.forEach(action: (view: View) -> Unit) {
    for (index in 0 until childCount) {
        action(getChildAt(index))
    }
}
```

また、IterableやSequenceに変換する拡張関数を定義しておけば、これらをレシーバーとする一連の拡張関数群が使えるようになります。

ここでは、CollectionでないけどCollectionのように扱いたくなるクラスをCollection的に扱う方法を紹介します。（すでにあるかもしれないが調べてない）

※安易に拡張関数を作ると混乱するので、使う際は各プロジェクト等のルールに従ってください。ご利用は自己責任で。

# 基本的な作業

基本的な作業は、Iteratorを定義することにつきます。
Iteratorは`next()`と`hasNext()`の2つのメソッドを定義すればよいだけですので簡単に作れます。
クラスとして定義してもいいですが、iterator()メソッドをoperatorとして定義すればそのままfor文で使えるようになるので以下のように定義してしまいましょう。

要するに、以下のように定義すると

```kotlin
operator fun Hoge.iterator(): Iterator<Fuga> = object : Iterator {
    override fun next(): Fuga = ...
    override fun hasNext(): Boolean = ...
}
```

以下のように書けるようになります。

```kotlin
for (fuga in hoge) { ... }
```

残念ながら`forEach`はこのままでは使えませんので、拡張関数の定義が必要です。が、`iterator()`を定義していれば一行です。

```kotlin
inline fun Hoge.forEach(action: (Node) -> Unit): Unit = iterator().forEach(action)
```

※iterator()のインスタンスを作成する分、多少効率は悪いとも言えますので、インスタンスを作成しないで簡単に書き下せる場合は、そちらで定義した方がよいと思います。


また、任意のコレクション操作を実現したい場合はIterableに変換してしまえばOKです。
Iterableは `iterator()` メソッド一つのインターフェースなので、以下のような定義になります。

```kotlin
fun Hoge.asIterable(): Iterable<Fuge> = Iterable { iterator() }
```

`asIterable()`はoperatorではないので、この名前でないといけないと言うことはありません。
Iterableに変換してしまえば以下のようにCollection操作メソッドが使えます。

```kotlin
hoge.asIterable()
    .filter { ... }
    .map { ... }
    .toSet()
```

forEachIndexed()も使えます。

```kotlin
hoge.asIterable().forEachIndexed { index, fuga ->
}
```

Iterableに変換する代わりにSequenceに変換するというのもありだと思います。Sequenceも`iterator()`メソッド一つのインターフェースで、Iterableと同じです。

```kotlin
fun Hoge.asSequence(): Sequence<Fuge> = Sequence { iterator() }
```

IterableからSequenceは`asSequence()`で、SequenceからIterableは`asIterable()`で簡単に相互変換可能なので使いやすい方を定義すればよいと思います。

### sequence関数/iterator関数

@sdkei さんから教えていただきました。（ありがとうございます）

`sequence`関数を使うとイテレート処理ほぼそのままでSequenceを作ることができます。
先のViewGroupでやるとこうです。

```kotlin
fun ViewGroup.asSequence(): Sequence<View> = sequence {
    for (index in 0 until childCount) {
        yield(getChildAt(index))
    }
}
```

残念ながら iterable 関数はないみたいですが、`iterator`関数はあります。使い方は全く同じ。

```kotlin
operator fun ViewGroup.iterator(): Iterator<View> = iterator {
    for (index in 0 until childCount) {
        yield(getChildAt(index))
    }
}
```

`sequence`/`iterator`関数が受け取るのは、SequenceScopeをレシーバーとするサスペンドラムダです。
SequenceScopeは`yield`と`yieldAll`(引数はIterator/Iterable/Sequence)というサスペンド関数を持っており、`yield`に値を渡した順に取り出されるSequenceを作ることができます。coroutinesをこういう風に使うこともできるのかと感心しました。

Iteratorとしての実装を考えるより、イテレート処理を書けば、それがそのままSequenceやIteratorになるので直感的かつスマートに実装することができますね。

# 事例集

結局のところ、Iteratorさえ定義してしまえば、他はほぼコピペみたいなものなので、以降はIteratorの作り方集みたいになります。`asIterable`とかの定義は省略するので適宜補完してください。

## org.w3c.dom

DOMを操作する際、特に読み込みではループを多用することになりますが、これらもCollectionだったりIteratorだったりはないので、while文などを使う必要があります。これらは拡張関数を用意すると便利です。

### Node

Nodeは `getNextSibling()` を使って隣接ノードを見ていくループをよく使いますね。
しかし、そのまま使おうとすると do ~ while を使ったりとなかなかスマートに使えないですね。

```kotlin
var node: Node? = ...
do {
   ...
   node = node.nextSigling
} while(node != null)
```

`iterator()`の定義

```kotlin
operator fun Node.iterator(): Iterator<Node> = object : Iterator<Node> {
    private var node: Node? = this@iterator
    override fun next(): Node = node?.also { node = it.nextSibling }
        ?: throw NoSuchElementException()
    override fun hasNext(): Boolean = node != null
}
```

これでスマートにいけます。

`iterator`関数を使うなら以下ですが、`iterator`関数に片引き数がないと`yield`で`!!`が必要になるのでちょっとややこしい

```kotlin
operator fun Node.iterator(): Iterator<Node> = iterator<Node> {
    var node: Node? = this@iterator
    while(node != null) {
        yield(node)
        node = node.nextSibling
    }
}
```

#### Elementだけ取りたいんや

```kotlin
node.asIterable()
    .mapNotNull { it as? Element }
```

で、十分すね。

Iterator書いた後に気づいたorz

### NodeList

Nodeの子要素のイテレートをしたい場合、`getFirstChild()`で最初の子要素を取り出して、`getNextSigling()`でイテレートするか、`getChildNodes()` でNodeListを取り出して、これをイテレートするかになります。

NodeListは以下のようなインターフェースです。

```java
public interface NodeList {
    public Node item(int index);
    public int getLength();
}
```

for文を書くだけならこんな感じで行けます。

```kotlin
for (i in 0 until nodeList.length) {
    val node = nodeList.item(i)
    ...
}
```

Iteratorにするにはこう

```kotlin
operator fun NodeList.iterator(): Iterator<Node> = object : Iterator<Node> {
    private var index = 0
    override fun next(): Node = item(index++)
    override fun hasNext(): Boolean = index < length
}
```

`iterator`関数を使うなら

```kotlin
operator fun NodeList.iterator(): Iterator<Node> = iterator {
    for (i in 0 until length) yield(item(i))
}
```

NodeListのイテレートはchildNodesに対して行うことが多いのと、隣接ノードでのイテレートと区別するため、以下のような拡張関数を定義しておけばいいかなと思います。

```kotlin
fun Node.siblings(): Iterable<Node> = Iterable { iterator() }
fun Node.siblingElements(): Iterable<Element> = siblings().mapNotNull { it as? Element }
fun NodeList.asIterable(): Iterable<Node> = Iterable { iterator() }
fun NodeList.asElementIterable(): Iterable<Element> = asIterable().mapNotNull { it as? Element }
fun Node.children(): Iterable<Node> = childNodes.asIterable()
fun Node.childElements(): Iterable<Element> = childNodes.asElementIterable()
```

### NamedNodeMap

Nodeから`getAttributes()`でAttributesを取り出してイテレートする場合があります。
これは NamedNodeMap なのでこいつに対しても定義します。NamedNodeMapは名前をキーに取り出すMapとしての機能がありますが、イテレートするために必要なメソッドはNodeListと同一なので以下のようになります。

```kotlin
operator fun NamedNodeMap.iterator() = object : Iterator<Node> {
    private var index = 0
    override fun next(): Node = item(index++)
    override fun hasNext(): Boolean = index < length
}
```

`iterator`関数を使うなら

```kotlin
operator fun NamedNodeMap.iterator(): Iterator<Node> = iterator {
    for (i in 0 until length) yield(item(i))
}
```

## Enumration

`NetworkInterface.getNetworkInterfaces()`の戻り値は`Enumration<NetworkInterface>`であり、EnumrationはCollectionでもIteratorでもありません。以下のようにIteratorのメソッド名が違うだけの Java1.0 からあるレガシーなインターフェースです。それだけに特にコードを書かずとも変換する手段が提供されているので、それを利用しましょう。

```java
public interface Enumeration<E> {
    boolean hasMoreElements();
    E nextElement();
}
```

Javaの世界でもCollectionsにArrayListに詰め替えるメソッドが存在しますし、

```java
public static <T> ArrayList<T> list(Enumeration<T> e) {
    ArrayList<T> l = new ArrayList<>();
    while (e.hasMoreElements())
        l.add(e.nextElement());
    return l;
}
```

KotlinではCollectionsJVM.ktにて上記`Collections.list`メソッドを使った

```kotlin
@kotlin.internal.InlineOnly
public inline fun <T> java.util.Enumeration<T>.toList(): List<T> = java.util.Collections.list(this)
```

という拡張関数が用意されていますので、`toList()` してしまえばあとはListとして扱えます。

さらに言えば、Java9以降ならasIterator()のデフォルトメソッドがあったりするので、使える環境ならこれを使えばよいですね。

```java
default Iterator<E> asIterator() {
    return new Iterator<>() {
        @Override public boolean hasNext() {
            return hasMoreElements();
        }
        @Override public E next() {
            return nextElement();
        }
    };
}
```

# まとめ

XML扱う処理書いてて、Iterator作ればええやんと気づいたので書き始めたのだが、結構バリエーションあるかなと思いきやネタ切れ、思いついたら追記するかも。