Например, у нас есть список, который мы хотим разделить на две части с помощью определенного предиката.

Во-первых, мы можем использовать filter и filterNot.

val trueList = list.filter(predicate)
val falseList = list.filterNot(predicate)

Во-вторых, мы можем использовать filter и subtract:

val trueList = list.filter(predicate)
val falseList = list.subtract(trueList)

В-третьих, мы можем использовать groupBy:

val groupBy = list.groupBy(predicate)
val trueList = groupBy[true]
val falseList = groupBy[false]

Какой способ самый эффективный и быстрый? А можем ли мы сделать это с помощью каких-то других функций?

Думаю, второй вариант с subtract худший, верно?

3
Daria Pydorenko 17 Май 2018 в 16:13

1 ответ

Лучший ответ

Итак, я попытался понять, какой вариант самый быстрый: filter, subtract, groupBy или partition (спасибо Марко Топольник за подсказку). И я использовал measureTimeMillis, чтобы узнать истекшее время каждого варианта:

private fun checkTime(list: List<Int>, predicate: (Int) -> Boolean) {
    var sum = 0L
    repeat(times) { sum += checkPartition(list, predicate) }
    println("partition: ${sum/times}")

    sum = 0L
    repeat(times) { sum += checkFilter(list, predicate) }
    println("filter: ${sum/times}")

    sum = 0L
    repeat(times) { sum += checkSubtract(list, predicate) }
    println("subtract: ${sum/times}")

    sum = 0L
    repeat(times) { sum += checkGroupBy(list, predicate) }
    println("group by: ${sum/times}")
}


private fun checkGroupBy(list: List<Int>, predicate: (Int) -> Boolean): Long {
    return measureTimeMillis {
        val groupBy = list.groupBy(predicate)
        val falseList = groupBy[false]
        val trueList = groupBy[true]
    }
}

private fun checkSubtract(list: List<Int>, predicate: (Int) -> Boolean): Long {
    return measureTimeMillis {
        val trueList = list.filter(predicate)
        val falseList = list.subtract(trueList)
    }
}

private fun checkFilter(list: List<Int>, predicate: (Int) -> Boolean): Long {
    return measureTimeMillis {
        val trueList = list.filter(predicate)
        val falseList = list.filterNot(predicate)
    }
}

private fun checkPartition(list: List<Int>, predicate: (Int) -> Boolean): Long {
    return measureTimeMillis {
        val pair = list.partition(predicate)
        val trueList = pair.first
        val falseList = pair.second
    }
}

Я проверил это с 10-кратным повторением и таким предикатом:

val predicate = { it: Int -> it % 2 == 0 }

И со списками другого размера:

var list = (1..1_000_000).toList()
checkTime(list, predicate)

раздел: 16 фильтр: 21 вычесть: 81 группировать по: 18

list = (1..2_000_000).toList()
checkTime(list, predicate)

раздел: 30 фильтр: 42 вычесть: 241 группировать по: 36

list = (1..3_000_000).toList()
checkTime(list, predicate)

раздел: 35 фильтр: 59 вычесть: 233 группировать по: 63

Итак, раздел - действительно хороший вариант для разделения список на две части.

Подскажите, пожалуйста, если я что-то не так сделал.

4
Daria Pydorenko 17 Май 2018 в 14:11