Peter
Peter

Reputation: 1582

Kotlin: iterate through array in reversed order

Is there a convenient way in Kotlin to iterate through an array, let's say IntArray, in reversed order with these 2 conditions:

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 IntArrays:

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

Answers (3)

Paolo
Paolo

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

Rajan Kali
Rajan Kali

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

Adam Millerchip
Adam Millerchip

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

Related Questions