lik*_*ern 4 iteration iterator kotlin
在Kotlin文档中,我发现了以下示例:
for ((index, value) in array.withIndex()) {
println("the element at $index is $value")
}
Run Code Online (Sandbox Code Playgroud)
是否有可能(以及如何)使用2D矩阵进行类似的操作:
for ((i, j, value) in matrix2D.withIndex()) {
// but iterate iver double index: i - row, j - column
if (otherMatrix2D[i, j] > value) doSomething()
}
Run Code Online (Sandbox Code Playgroud)
如何在Kotlin类中支持此功能?
这两种语言功能用于实现您想要的行为:
For循环可以与任何具有提供迭代器的方法的类一起使用.
for (item in myItems) { ... }
Run Code Online (Sandbox Code Playgroud)
如果myItems函数iterator()返回函数hasNext(): Boolean和函数,则此代码将编译next().
通常它是一个Iterable<SomeType>实现(某些集合),但您可以将iterator()方法作为扩展添加到现有类,并且您也可以在for循环中使用该类.
对于解构声明,项类型应具有componentN()函数.
val (x, y, z) = item
Run Code Online (Sandbox Code Playgroud)
这里编译器期望item有component1(),component2()和component3()功能.您也可以使用data类,它们生成了这些函数.
for循环中的解构以类似的方式工作:迭代器next()返回的类型必须具有componentN()函数.
具有解构支持的类:
class Cell<T>(val i: Int, val j: Int, val item: T) {
operator fun component1() = i
operator fun component2() = j
operator fun component3() = item
}
Run Code Online (Sandbox Code Playgroud)
或者使用data课程:
data class Cell<T>(val i: Int, val j: Int, val item: T)
Run Code Online (Sandbox Code Playgroud)返回的函数List<Cell<T>>(写为扩展名,但也可以是成员函数):
fun <T> Matrix<T>.withIndex() =
(0 .. height - 1).flatMap { i ->
(0 .. width - 1). map { j ->
Cell(i, j, this[i, j])
}
}
Run Code Online (Sandbox Code Playgroud)用法:
for ((i, j, item) in matrix2d.withIndex()) { ... }
Run Code Online (Sandbox Code Playgroud)Michael提供的UPD解决方案实际上表现更好(运行此测试,差异大约是2x到3x),因此它更适合性能关键代码.
虽然miensol和hotkey提出的解决方案是正确的,但它是迭代矩阵的最低效方法.例如,溶液热键使M * N的分配Cell<T>加M的分配List<Cell<T>>和IntRange加一个分配List<List<Cell<T>>>和IntRange.此外,列表会在添加新单元格时调整大小,因此会发生更多分配.这只是迭代矩阵的分配太多了.
我建议你实现一个非常相似且非常有效的扩展功能,它将类似于Array<T>.forEachIndexed.该解决方案根本不进行任何分配,并且与编写嵌套for循环一样有效.
inline fun <T> Matrix<T>.forEachIndexed(callback: (Int, Int, T) -> Unit) {
for (i in 0..cols - 1) {
for (j in 0..rows - 1) {
callback(i, j, this[i, j])
}
}
}
Run Code Online (Sandbox Code Playgroud)
您可以通过以下方式调用此函数:
matrix.forEachIndexed { i, j, value ->
if (otherMatrix[i, j] > value) doSomething()
}
Run Code Online (Sandbox Code Playgroud)
如果for由于某种原因想要使用具有破坏性声明的传统-loop,那么存在一种更有效但是hacky解决方案的方法.它使用序列而不是分配多个列表并仅创建单个实例Cell,但它Cell本身是可变的.
data class Cell<T>(var i: Int, var j: Int, var value: T)
fun <T> Matrix<T>.withIndex(): Sequence<Cell<T>> {
val cell = Cell(0, 0, this[0, 0])
return generateSequence(cell) { cell ->
cell.j += 1
if (cell.j >= rows) {
cell.j = 0
cell.i += 1
if (cell.i >= cols) {
return@generateSequence null
}
}
cell.value = this[cell.i, cell.j]
cell
}
}
Run Code Online (Sandbox Code Playgroud)
您可以使用此函数迭代for-loop中的矩阵:
for ((i, j, item) in matrix.withIndex()) {
if (otherMatrix[i, j] > value) doSomething()
}
Run Code Online (Sandbox Code Playgroud)
这个解决方案比第一个解决方案效率低得多,并且因为可变性而不那么强大Cell,所以我建议你使用第一个解决方案.
| 归档时间: |
|
| 查看次数: |
98 次 |
| 最近记录: |