Reputation: 1582
Is there a convenient way in Kotlin to iterate through an array, let's say IntArray
, in reversed order with these 2 conditions:
for
.The best I could get is adding an extension function, but this needs to be done for each type of array if I need it not only for IntArray
s:
fun IntArray.forEachReversed(action: (Int) -> Unit): Unit {
for (i in indices.reversed()) action(this[i])
}
Is there a better way in Kotlin class library?
Upvotes: 1
Views: 2603
Reputation: 595
As pointed out by @ajan.kali if you need primitive arrays there is not much you can do. I suppose you have to deal with arrays but, if this is not the case, you should prefer other data structures (more info here) Returning to your question, if your are fine using generic arrays you could probably declare your iterator to iterate in reverse order:
class ReverseIterator<T>(val it: Iterable<T>) : Iterator<T> {
private var index = it.count() - 1
override fun hasNext() = index >= 0
override fun next(): T = try { it.elementAt(index--) } catch (e:
IndexOutOfBoundsException) { index -= 1; throw
NoSuchElementException(e.message) }
}
then your extension function will become:
fun <T> Iterable<T>.forEachReversed(action: (T) -> Unit) {
for(elem in ReverseIterator(this)) {
action(elem)
}
}
and then given an array you can invoke it this way:
intArrayOf(1, 2, 3).asIterable().forEachReversed {
println(it)
}
Not particularly happy with this, but with arrays there is not much you can do other to try avoiding them.
Upvotes: 0
Reputation: 12953
To answer you question, you solution looks fine but if your are targeting primitive IntArray
, LongArray
, FloatArray
etc you cannot come with a generic solution, as this classes are independent and only thing common is Iterator
, but you cannot traverse the iterator
in reverse order without making a copy(ListIterator
supports reverse iteration though), but the closest you can get is to use Array<T>
instead specific Array like below
fun <T> Array<T>.forEachReversed(action: (T) -> Unit){
for(i in indices.reversed()){ action(this[i]) }
}
val intArray = Array(2){ 0 }
val longArray = Array<Long>(2){ 0 }
intArray.forEachReversed { }
longArray.forEachReversed { }
Upvotes: 0
Reputation: 23091
this needs to be done for each type of array if I need it not only for IntArrays:
I think this is unavoidable because of the way the JVM works. There are separate classes to represent each primitive type on the JVM. However, there are only 8 of them, so it shouldn't be too bad ;-)
For Collections, there is the asReversed()
function, but it's not available for arrays:
val original = mutableListOf('a', 'b', 'c', 'd', 'e') val originalReadOnly = original as List<Char> val reversed = originalReadOnly.asReversed() println(original) // [a, b, c, d, e] println(reversed) // [e, d, c, b, a] // changing the original list affects its reversed view original.add('f') println(original) // [a, b, c, d, e, f] println(reversed) // [f, e, d, c, b, a]
Upvotes: 1