如何解决Kotlin - 在索引范围内的 IntArray 中查找最小值
我正在将一些旧的 Java 代码重构到 Kotlin。有一个函数返回 Kotlin IntArray
范围内的元素所持有的最小值的索引,范围为 [a
,b
]。范围值默认为 0,数组大小默认为 1。
我想做一些类似……的事情
return data.minOf().indexOf()
...但只在 a
的 b
和 data
索引之间迭代。
功能如下:
// data is the IntArray property that I'm looping through.
fun absMinIndex(a: Int = 0,b: Int = (data.size - 1)) : Int {
var minVal = data[a]
var minIndex = 0
for (i in (a + 1)..b) {
val e = data[i]
if (e < minVal) {
minVal = e
minIndex = i
}
}
return maxIndex
}
这个 [for 循环] 通过从不访问超出范围的索引,并且不生成复制的数组/子数组,很好地解决了这个问题。我想知道它是否可以做得“更漂亮”。
问题
是否有更惯用的 Kotlin 方法在不会对我当前解决方案的性能产生负面影响的范围内迭代数组?
为了清晰起见编辑了一些代码。
解决方法
我相信这种方法会更惯用:
- 使用
IntRange
作为输入参数 - 为
IntArray
定义扩展方法,提供自定义迭代器以将所需范围内的列表遍历到IndexedValue
中:
fun IntArray.withIndexInRange(range: IntRange = 0..lastIndex) = Iterable {
require(range.first >= 0 && range.last <= lastIndex)
object : Iterator<IndexedValue<Int>> {
private var index = range.first
override fun hasNext() = index <= range.last
override fun next() = IndexedValue(index,this@withIndexInRange[index++])
}
}
- 使用 stdlib 中的
minByOrNull
方法查找最小值或为方便起见将其包装到另一个扩展方法中:
fun <T : Comparable<T>> Iterable<IndexedValue<T>>.indexOfMinOrNull() = minByOrNull { it.value }?.index
用法:
data.withIndexInRange(a..b).indexOfMinOrNull()
请注意,这会带来一些性能损失(创建和 GC 的 N 个额外对象),但正如 Donald Knuth 所说:
过早优化是万恶之源
所以,我相信更好的可读性是值得的。
,正如 Tenfour04 所建议的那样,在不降低性能的情况下您无能为力。但是按照你的想法,改变你调用它的方式,你可以把它变成一个扩展函数。
fun IntArray.findIndexOfMinInRange(a: Int = 0,b: Int = this.size - 1): Int {
var maxVal = get(a)
var maxIndex = 0
for (i in (a + 1)..b) {
if (get(i) < maxVal) {
maxVal = get(i)
maxIndex = i
}
}
return maxIndex
}
//and call it like this:
data.findIndexOfMinInRange(0,15) //or without anything in the parentheses for the default values
我要更改的一件事是函数内的变量名称,我们正在搜索最小值,而不是最大值,以及最小值的索引,而不是最大值索引。也可能(可能)创建一个 data[it]
的 val 而不是访问它两次可能会更好(老实说不确定,我们会用 .get
换取几个字节的内存)。
总而言之,我可能会留在这里:
fun IntArray.findIndexOfMinInRange(fromIndex: Int = 0,toIndex: Int = this.size - 1): Int {
var min = get(fromIndex)
var indexOfMin = fromIndex
for(i in (fromIndex + 1)..toIndex){
val current = get(i)
if (current < min) {
min = current
indexOfMin = i
}
}
return indexOfMin
}
//would be called in the same way the one above
另外,请注意,如果您创建了一个特定大小的 IntArray
,并且没有完全填充它,那么它将为未填充的默认值保留为 0
。如果你这样做:
val data = IntArray(6)
data[0] = 10
data[1] = 11
data[2] = 100
data[3] = 9
data[4] = 50
那么实际的数组是[10,11,100,9,50,0]
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。