Kotlin: Iterate through a JSONArray

AndroidJsonKotlin

Android Problem Overview


I'm writing an Android app using Kotlin and Realm. I have a JSONArray, and I want to iterate through the JSONObjects in this array in order to load them in a Realm database class:

Realm class:

import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
import io.realm.annotations.Required

open class Person(

        @PrimaryKey open var id: Long = 0,

        @Required
        open var name: String = ""

) : RealmObject() {

}

The JSONArray:

{
    "persons":[
        {
           "id":0,
           "name":"Biatrix"
        },
        {
           "id":1,
           "name":"Bill"
        },
        {
           "id":2,
           "name":"Oren"
        },
        {
           "id":3,
           "name":"Budd"
        }
    ]
}

I've tried iterating like the following:

for (item : JSONObject in persons) {

}

... but I get a for-loop range must have an iterator() method error.

Android Solutions


Solution 1 - Android

Unfortunately, JsonArray does not expose an iterator. So you will have to iterate through it using an index range:

for (i in 0 until persons.length()) {
    val item = persons.getJSONObject(i)
    
    // Your code here
}

Solution 2 - Android

Even if some class doesn't expose an iterator method, you can still iterate it with for statement by providing an extension function iterator:

operator fun JSONArray.iterator(): Iterator<JSONObject> 
    = (0 until length()).asSequence().map { get(it) as JSONObject }.iterator()

Now when you use JSONArray in for statement this extension is invoked to get an iterator. It creates a range of indices and maps each index to an item corresponding to this index.

I suppose the cast to JSONObject is required as the array can contain not only objects but also primitives and other arrays. And the asSequence call is here to execute map operation in a lazy way.

Generic way (assuming all array entries are of same type)

@Suppress("UNCHECKED_CAST")
operator fun <T> JSONArray.iterator(): Iterator<T>
    = (0 until length()).asSequence().map { get(it) as T }.iterator()

Solution 3 - Android

How about

(0..(jsonArray.length()-1)).forEach { i ->
    var item = jsonArray.getJSONObject(i)
}

?

Solution 4 - Android

for (i in 0 until jsonArray.length()){
    //do your stuff
    }

Solution 5 - Android

shortest way is:

(0 until persons.length()).forEach {
    val item = persons.getJSONObject(it)

Basically from a range taking from zero to the jsonarray lenght ,it takes one number at time and use it as a index to retrieve the current object

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAmbranView Question on Stackoverflow
Solution 1 - Android0x60View Answer on Stackoverflow
Solution 2 - AndroidIlyaView Answer on Stackoverflow
Solution 3 - AndroidSharifView Answer on Stackoverflow
Solution 4 - AndroidMorpheusView Answer on Stackoverflow
Solution 5 - AndroidfisioView Answer on Stackoverflow