Более идиоматический способ инициализации набора в Kotlin?

#kotlin #initialization #set

#kotlin #инициализация #набор

Вопрос:

У меня есть набор ячеек
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)
        }
    }
}
  

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

Ответ №1:

Вы могли бы определить расширение, которое использует преобразователь для получения комбинаций в виде пары целых чисел, а затем сопоставить его с 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) } }
  

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

Ответ №2:

К сожалению, нет конструктора или функции верхнего уровня, чтобы упростить создание набора, следующего определенной логике, но если у вас уже есть список, вы можете превратить его в Set using 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()
  

Ответ №3:

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

 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)
}