在 Kotlin 中将二维数组的迭代器展平

3

我有一个Grid类,它是Cell对象的2D数组包装器。我希望这个类实现Iterable<Cell>接口,以便在循环中使用它并直接遍历所有单元格。有没有简单的方法来做到这一点?Kotlin是否支持yield return样式的迭代器?我的当前解决方案相当冗长:

override fun iterator() = object : Iterator<Cell> {
    val currentOuter = grid.iterator() // grid is object of Array<Array<Cell>>
    var currentInner = if (currentOuter.hasNext()) currentOuter.next().iterator() else arrayOf<Cell>().iterator()

    override fun next(): Cell {
        if (!hasNext()) {
            throw NoSuchElementException()
        }

        return if (currentInner.hasNext()) {
            currentInner.next()
        } else {
            currentInner = currentOuter.next().iterator()
            currentInner.next()
        }
    }

    override fun hasNext(): Boolean {
        return currentInner.hasNext() || currentOuter.hasNext()
    }
}
2个回答

5
Kotlin是否支持yield return风格的迭代器? 是的,通过协程功能支持。这里有一个自包含示例:
data class Cell(val d: Int)

val grid: Array<Array<Cell>> = arrayOf(arrayOf(Cell(1), Cell(2)), arrayOf(Cell(3), Cell(4)))

fun cellSequence() = buildSequence {
    grid.forEach { it.forEach { yield(it) } }
}

fun main(args: Array<String>) {
    cellSequence().forEach { println(it) }
}

尽管这个问题可以通过使用 flatMap 简单解决,但是所呈现的代码可以作为编写任何类似过程式代码的模板,例如:
fun complexCellSequence() = buildSequence {
    yield(Cell(-1))
    if (grid.size <= 2) {
        yield(Cell(2))
    }
    for (row in grid) {
        if (row.contains(Cell(1))) {
            yield(Cell(1))
        } else {
            yield(Cell(12))
            row.forEach { yield(it) }
        }
    }
}

这将是一个没有协程很难重写的问题。

3
一个非常简单的解决方案可以像这样:

如下代码:

val grid: Array<Array<Cell>> = ...

override fun iterator() : Iterator<Cell> = grid.flatMap { it.asList() }.iterator()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接