Найти первый и преобразовать для последовательности в Kotlin - PullRequest
0 голосов
/ 09 февраля 2019

Я часто сталкиваюсь с этой проблемой, но не вижу общей реализации: как мне идиоматически (функционально) найти элемент, остановить поиск после совпадения, а также вернуть другой тип (т. Е. Сопоставить любое совпадение с другим типом)?

Я смог сделать обходной путь с

fun <F,T> Sequence<F>.mapFirst(block: (F) -> T?): T? =
    fold(AtomicReference<T>()) { ref, from ->
        if (ref.get() != null) return@fold ref
        ref.set(block(from))
        ref
    }.get()

fun main() {
    Files.list(someDir).asSequence().map { it.toFile() }.mapFirst { file ->
        file.useLines { lines ->
            lines.mapFirst { line ->
                if (line == "123") line.toInt() else null
            }
        }
    }?.let { num ->
        println("num is $num") // will print 123 as an Int
    } ?: println("not a single file had a line eq to '123'")
}

Но это не останавливается на совпадении (когда block() возвращает ненулевое значение) и использует все файлыи все их линии.

Ответы [ 2 ]

0 голосов
/ 09 февраля 2019

Я бы тогда не отображал значения, которые вы отбрасываете, вместо этого сделайте это следующим образом:

sequenceOf(1, 2, 3)
    .firstOrNull() { it == 2 }
    ?.let { it * 2 } ?: 6

Сначала вы найдете значение, соответствующее вашему условию, а затем преобразуете его тоже, что хотите.Если вы не нашли соответствующий элемент, вы назначаете значение по умолчанию (в данном случае 6).

0 голосов
/ 09 февраля 2019

Простого цикла for достаточно для реализации mapFirst:

fun <F,T> Sequence<F>.mapFirst(block: (F) -> T?): T? {
    for (e in this) { 
        block(e)?.let { return it }
    }
    return null
}

Если вам нужно решение без введения собственных расширений (хотя в этом нет ничего плохого), вы можете использовать mapNotNull + firstOrNull комбинация:

files.asSequence()
    .mapNotNull { /* read the first line and return not null if it's ok */ }
    .firstOrNull()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...