KotlinでもClojureの便利な関数を使いたい

関数型言語に特有？のリスト操作系の関数をKotlinではどうすれば使えるのか調べて＆作ってみました。

# リストの構築
```range.clj
(def list1 (range 1 6))
(def list2 [6 6 7 8 7 7])
```
```range.kt
val list1 = IntRange(1, 5)
val list2 = listOf(6, 6, 7, 8, 7, 7)
```
KotlinのほうはClosedRangeなんですね。

## リストの連結
```concat.clj
(conj list2 10)
(concat list1 list2)
```
```concat.kt
list2 + 10
list1 + list2
```

## 無限リスト
```repeat.clj
(->> (repeat 123) (take 3))
(->> (iterate #(* 4 %) 3) (take 3))
```
```repeat.kt
generateSequence { 123 }.take(3)
generateSequence(3) { it * 4 }.take(3)
```

# リストの操作（基本）
## フィルタリング
### filter, remove
```filter.clj
(filter even? list1)
(remove even? list1)
```
```filter.kt
list1.filter { it % 2 == 0 }
list1.filterNot { it % 2 == 0 }
```

### some
```some.clj
(some #(when (even? %) %) list1)
```
```some.kt
list1.find { it % 2 == 0 }
list1.first { it % 2 == 0 }
```
条件に合致するものがなかった場合、findはnullを返し、firstは例外発生になります。

## マッピング
```map.clj
(map #(* % 2) list1)
(keep #(when (> % 3) (* % 2)) list1)
(map-indexed #(* %1 %2) list1)
(keep-indexed #(when (> % 3) (* % %2)) list1)
(mapcat #(list % (* % %)) list1)
```
```map.kt
list1.map { it * 2 }
list1.mapNotNull { if (it > 3) it * 2 else null }
list1.mapIndexed { i, v -> i * v }
list1.mapIndexedNotNull { i, v -> if (i > 3) i * v else null }
list1.flatMap { listOf(it, it * it) }
```

## 畳みこみ
```reduce.clj
(reduce #(* %1 %2) input)
(reduce #(* %1 %2) 10 input)
(reduce #(if (> % 20) (reduced %) (* % %2)) input)
```
```reduce.kt
list1.reduce { acc, v -> acc * v }
list1.fold(10) { acc, v -> acc * v },
list1.reduce { acc, v -> if (acc > 20) return@reduce acc else acc * v }
```

reduceを途中でやめたいときはラベル付きreturnが使えます。

# リストの操作（応用）

だんだん作らないといけないものが増えてきます。

## 重複削除、連続する重複を削除
```distinct.clj
(distinct list2)
(dedupe list2)
```
```distinct.kt
fun <T> Iterable<T>.dedupe(): List<T> {
    if (count() == 0) return toList()
    return fold(listOf(first())) { acc, v -> if (v != acc.last()) acc + v else acc }
}

list2.distinct()
list2.dedupe()
```

## シャッフル
```shuffle.clj
(shuffle list2)
```
```shuffle.kt
import java.util.Collections

fun <T> Iterable<T>.shuffle(): List<T> = toMutableList().apply { Collections.shuffle(this) }

list2.shuffle()
```

applyは便利ですね。

## グループ化Map、出現回数Mapの構築
```groupby.clj
(group-by #(mod % 2) list2)
(frequencies list2)
```
```groupby.kt
fun <T> Iterable<T>.frequencies(): Map<T, Int> = groupingBy { it }.eachCount()

list2.groupBy { it % 2 }
list2.frequencies()
```

## 値のはさみ込み
```interleave.clj
(interleave list1 list2)
(interpose 999 list1)
```
```interleave.kt
fun <T> Iterable<T>.interleave(list: Iterable<T>): List<T> = zip(list).flatMap { it.toList() }

fun <T> Iterable<T>.interpose(sep: T): List<T> =
        zip(Collections.nCopies(count(), sep)).flatMap { it.toList() }.dropLast(1)

list1.interleave(list2)
list1.interpose(999)
```

## 累積計算
```reductions.clj
(reductions * list1)
(reductions * 10 list1)
```
```reductions.kt
fun <T> Iterable<T>.reductions(function: (T, T) -> T): List<T> {
    if (count() <= 1) return toList()
    return drop(1).reductions(first(), function)
}

fun <T, R> Iterable<T>.reductions(init: R, function: (R, T) -> R): List<R> {
    if (count() == 0) return listOf(init)
    return fold(listOf(init)) { acc, v -> acc + function(acc.last(), v) }
}

list1.reductions { i, j -> i * j }
list1.reductions(10, Int::times)
```

## n個おきにリストを分割
```partition.clj
(partition 3 list1)
(partition-all 3 list1)
(partition 4 2 list1)
(partition-all 4 2 list1)
(partition 4 2 [:a :b] list1)
```
```partition.kt

fun <T> Iterable<T>.partition(n: Int, step: Int = n, pad: List<T> = listOf<T>()): List<List<T>> {
    var tmp = toList()
    return mutableListOf<List<T>>().apply {
        while (tmp.count() >= n) {
            add(tmp.take(n))
            tmp = tmp.drop(step)
        }
        if (!pad.isEmpty() && !tmp.isEmpty())
            add((tmp + pad).take(n))
    }
}

fun <T> Iterable<T>.partitionAll(n: Int, step: Int = n): List<List<T>> {
    var tmp = toList()
    return mutableListOf<List<T>>().apply {
        while (!tmp.isEmpty()) {
            add(tmp.take(n))
            tmp = tmp.drop(step)
        }
    }
}

list1.partition(3)
list1.partitionAll(3)
list1.partition(4,2)
list1.partitionAll(4,2)
list1.partition(4,2,listOf("a","b"))
```

Kotlinにもともとあるpartition関数は`Pair<List<T>, List<T>>`を返すので用途が違います。

## 条件によってリストを分割
```partitionby.clj
(partition-by identity list2)
(partition-by #(> % 7) list2)
```
```partitionby.kt
fun <T, R> Iterable<T>.partitionBy(function: (T) -> R): List<List<T>> {
    if (count() == 0) return listOf()

    return drop(1).fold(listOf(listOf(first()))) { acc, v ->
        if (function(acc.last().last()) != function(v))
            acc + listOf(listOf(v))
        else
            acc.dropLast(1) + listOf(acc.last() + v)
    }
}

list2.partitionBy { it }
list2.partitionBy { it > 7 }
```