0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Kotlin】List<Before> を List<After> に変換する関数を一度だけ使って List<Before?> を List<After?> に変換する

Last updated at Posted at 2021-07-22

問題

List<Before?> 型の値を List<After?> 型に変換したい。
要素の値が null であれば null のまま、Before であれば After に変換する。

変換には、List<Before> 型の値を List<After> 型に変換する関数を
一度だけ1使用したい。
この関数は null を受け付けないことに注意。

Before 型、After 型、および List<Before> 型の値を List<After> 型に変換する関数を、仮に次のようなものとする。

data class Before(val value: String)
data class After(val value: String)

fun List<Before>.toAfterList(): List<After> =
    map { After(it.value) }

解答

次のような関数を用いることで変換できる。

fun List<Before?>.toAfterOrNullList(): List<After?> {
    val beforeOrNullList = this
    val afterItr: Iterator<After> = beforeOrNullList
        .filterNotNull()
        .toAfterList()
        .iterator()
    return beforeOrNullList.map { beforeOrNull ->
        beforeOrNull?.run {
            afterItr.next()
        }
    }
}

動作確認

fun main() {
    listOf(Before("A"), Before("B")).also {
        println("$it -> ${it.toAfterOrNullList()}")
        // ^ > [Before(value=A), Before(value=B)] -> [After(value=A), After(value=B)]
    }
    listOf(Before("A"), null).also {
        println("$it -> ${it.toAfterOrNullList()}")
        // ^ > [Before(value=A), null] -> [After(value=A), null]
    }
    listOf(null, Before("B")).also {
        println("$it -> ${it.toAfterOrNullList()}")
        // ^ > [null, Before(value=B)] -> [null, After(value=B)]
    }
    listOf(null, null).also {
        println("$it -> ${it.toAfterOrNullList()}")
        // ^ > [null, null] -> [null, null]
    }
}

発展

一般化して、
List<T>List<R> に変換する関数を用いて
 List<T?>List<R?> に変換する関数」にする。

inline fun <T, R> List<T?>.mapWithNull(
    crossinline transform: (List<T>) -> List<R>
): List<R?> {
    val tOrNullList = this
    val rItr: Iterator<R> = tOrNullList
        .filterNotNull()
        .let(transform)
        .iterator()
    return tOrNullList.map { tOrNull ->
        tOrNull?.run {
            rItr.next()
        }
    }
}

関数名は改善の余地がありそう。

動作確認

fun main() {
    listOf(Before("A"), Before("B")).also {
        println("$it -> ${it.mapWithNull { it.toAfterList() }}")
        // ^ > [Before(value=A), Before(value=B)] -> [After(value=A), After(value=B)]
    }
    listOf(Before("A"), null).also {
        println("$it -> ${it.mapWithNull { it.toAfterList() }}")
        // ^ > [Before(value=A), null] -> [After(value=A), null]
    }
    listOf(null, Before("B")).also {
        println("$it -> ${it.mapWithNull { it.toAfterList() }}")
        // ^ > [null, Before(value=B)] -> [null, After(value=B)]
    }
    listOf(null, null).also {
        println("$it -> ${it.mapWithNull { it.toAfterList() }}")
        // ^ > [null, null] -> [null, null]
    }
}

/以上

  1. この関数は呼び出しコストが大きい。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?