39

I have an iterator of strings from fieldNames of JsonNode:

val mm = ... //JsonNode
val xs = mm.fieldNames()

I want to loop over the fields while keeping count, something like:

when mm.size() {
  1 -> myFunction1(xs[0])
  2 -> myFunction2(xs[0], xs[1])
  3 -> myFunction3(xs[0], xs[1], xs[2])
  else -> print("invalid")
}

Obviously the above code does not work as xs the Iterator cannot be indexed like so. I tried to see if I can convert the iterator to list by mm.toList() but that does not exist.

How can I achieve this?

breezymri
  • 3,975
  • 8
  • 31
  • 65
  • 1
    https://stackoverflow.com/questions/10117026/convert-iterator-to-arraylist tells you how to convert an iterator into a list in Java. It's trivial to do the same in Kotlin. – DPM Sep 08 '17 at 02:46

3 Answers3

57

Probably the easiest way is to convert iterator to Sequence first and then to List:

listOf(1,2,3).iterator().asSequence().toList()

result:

[1, 2, 3]
Aivean
  • 10,692
  • 25
  • 39
  • I used it as json.keys().iterator().asSequence().toList() – Aayush Dec 28 '19 at 19:07
  • `asSequence` is not required, it's redundant – xenoterracide Oct 06 '22 at 14:33
  • @xenoterracide are you sure about that? Just checked with Kotlin 1.7, skipping `asSequence` [doesn't work](https://play.kotlinlang.org/#eyJ2ZXJzaW9uIjoiMS43LjEwIiwiY29kZSI6ImZ1biBtYWluKCkge1xuXHRsaXN0T2YoMSwgMiwgMykuaXRlcmF0b3IoKS50b0xpc3QoKVxufSIsInBsYXRmb3JtIjoiamF2YSIsImFyZ3MiOiIifQ==) – Aivean Oct 07 '22 at 01:21
4

I would skip the conversion to sequence, because it is only a few lines of code.

fun <T> Iterator<T>.toList(): List<T> =
    ArrayList<T>().apply {
        while (hasNext())
            this += next()
    }

Update:

Please keep in mind though, that appending to an ArrayList is not that performant, so for longer lists, you are better off with the following, or with the accepted answer:

    fun <T> Iterator<T>.toList(): List<T> =
        LinkedList<T>().apply {
            while (hasNext())
                this += next()
        }.toMutableList()
andras
  • 3,305
  • 5
  • 30
  • 45
  • `Sequence.toList()` appends items to an `ArrayList` internally, so it must be performant. Which makes sense since each `LinkedList.add` requires an allocation while `ArrayList.add` reallocates the backing array with spare capacity for following elements. – Serid Feb 05 '23 at 20:02
4

You can turn an Iterator into an Iterable using Iterable { iterator } on which you can then call toList():

Iterable { listOf(1,2,3).iterator() }.toList() // [1, 2, 3]
Robert
  • 41
  • 2