Более идиоматический способ инициализации набора в Kotlin? - PullRequest
2 голосов
/ 22 апреля 2019

У меня есть набор ячеек
data class Cell(val i: Int, val j: Int)
, который я инициализирую в своем классе следующим образом:

protected val board = mutableSetOf<Cell>()
init {
    for (i in 1..width) {
        for (j in 1..width) {
            board += Cell(i, j)
        }
    }
}

Есть ли более идиоматический (функциональный) способ инициализации набора?
В идеале я хотел бы, чтобы набор был неизменным, потому что после этой инициализации он никогда не должен изменяться.

Ответы [ 3 ]

1 голос
/ 23 апреля 2019

К сожалению, нет конструктора или функции верхнего уровня, которая бы облегчала создание набора по определенной логике, но если у вас уже есть список, вы можете превратить его в Set, используя toSet().

В любом случае я бы отделил логику создания списка комбинаций и создания Cell экземпляров.

// extension property on IntRange to create all possible combinations
val IntRange.combinations get() = flatMap { i -> map { j -> i to j }}

val set = (1..5)
             .combinations
             .map { (i, j) -> Cell(i, j) }
             .toSet()

Добавление:

Если вы создаете вторичный конструктор для Cell, который принимает Pair, например:

data class Cell(val i: Int, val j: Int) {
    constructor(pair: Pair<Int, Int>): this(pair.first, pair.second)
}

, вы можете сократить код до этого:

val set = (1..5).combinations.map(::Cell).toSet()
1 голос
/ 22 апреля 2019

Вы можете определить расширение, которое принимает преобразователь для получения комбинаций в виде пары целых чисел, а затем сопоставить его с Cell.Например:

inline fun <R> IntRange.combine(block: (Int, Int) -> R): Set<R> {
    return flatMap { x -> map { y -> block(x, y) } }.toSet()
}

И затем вы можете инициализировать с помощью:

protected val board = (1..width).combine { x, y -> Cell(x, y) }

или просто:

protected val board = (1..width).flatMap { i -> (1..width).map { j -> Cell(i, j) } }

Я думаю, что первое более читабельно.

0 голосов
/ 23 апреля 2019

Вы можете сделать это

fun initBoard(width: Int): Set<Cell> {
    return List<Cell>(width * width) { index ->
            val i = index / width
            val j = index % width
            Cell(i + 1, j + 1)
    }.toSet()
}

тогда в вашем блоке инициализации

lateinit var board: Set<Cell>

init {
    board = initBoard(width)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...