Kotlin: Durch ein JSONArray iterieren

78

Ich schreibe eine Android-App mit Kotlin und Realm. Ich habe ein JSONArray und möchte die JSONObjects in diesem Array durchlaufen, um sie in eine Realm-Datenbankklasse zu laden:

Reichsklasse:

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() {

}

Das JSONArray:

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

Ich habe versucht, wie folgt zu iterieren:

for (item : JSONObject in persons) {

}

... aber ich bekomme eine for-loop range must have an iterator() methodFehlermeldung.

Ambran
quelle
Welche JSON-Bibliothek verwenden Sie?
mfulton26
Ich verwende das org.json.JSONArray und org.json.JSONObject.
Ambran

Antworten:

149

Leider wird JsonArraykein Iterator verfügbar gemacht. Sie müssen es also mithilfe eines Indexbereichs durchlaufen:

for (i in 0 until persons.length()) {
    val item = persons.getJSONObject(i)

    // Your code here
}
0x60
quelle
43
Schöner ist: für (i in 0 bis Personen.Länge ())
Zeiger Null
7
for(i in 0 until persons.length()ist definitiv schöner, da es zu helfen scheint, das gefürchtete Einzelproblem zu vermeiden. Aber warum sollte ein Iterator nicht entlarvt werden? Dies scheint standardmäßig verrückt zu sein ... es ist ein Kernobjekttyp, der sich vollständig auf mehrere Objekte konzentriert. Durchlaufen scheint nur natürlich, oder ???
Mike Williamson
Es hilft mir sehr. Danke Kerl.
marcode_ely
Ich habe eine Ausnahme außerhalb der Reichweite
Famfamfam
41

Auch wenn eine Klasse eine iteratorMethode nicht verfügbar macht , können Sie sie dennoch mit einer forAnweisung iterieren, indem Sie eine Erweiterungsfunktion bereitstellen iterator:

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

Jetzt, wenn Sie JSONArrayin verwendenfor Anweisung verwenden, wird diese Erweiterung aufgerufen, um einen Iterator zu erhalten. Es erstellt eine Reihe von Indizes und ordnet jeden Index einem Element zu, das diesem Index entspricht.

Ich nehme an, die Umwandlung in JSONObjectist erforderlich, da das Array nicht nur Objekte, sondern auch Grundelemente und andere Arrays enthalten kann. Und der asSequenceAufruf ist hier, um die mapOperation auf faule Weise auszuführen .

Generischer Weg ( vorausgesetzt, alle Array-Einträge sind vom gleichen Typ)

@Suppress("UNCHECKED_CAST")
operator fun <T> JSONArray.iterator(): Iterator<T>
    = (0 until length()).asSequence().map { get(it) as T }.iterator()
Ilya
quelle
3
Danke Ilya. Als Kotlin-Neuling schätze ich jeden Input, den ich bekommen kann.
Ambran
1
Ich bevorzuge diese Lösung, da sie die spezifische Funktionalität von Kotlin
besser
2
Natürlich haben Sie nicht immer ein Array von JSONObject. Vielleicht möchten Sie es versuchen: operator fun <T> JSONArray.iterator(): Iterator<T> = (0 until length()).asSequence().map { get(it) as T }.iterator()Jetzt hat es natürlich eine "ungeprüfte Besetzung".
AndroidGy
1
@Sevastyan 0 until length()erzeugt einen leeren Bereich, wenn ein Array leer ist, und getwird daher 0-mal (dh überhaupt nicht aufgerufen) für Elemente des leeren Bereichs aufgerufen.
Ilya
2
@Sevastyan können Sie schnell überprüfen, was 0 until 0mit try.kotlinlang.org
Ilya
3

Wie wäre es mit

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

?

Sharif
quelle
jsonArray.getJSONObject(r)sollte jsonArray.getJSONObject(i)oder habe ich etwas falsch verstanden?
Ambran
Ja, du hast recht, es sollte inicht sein r. Codebeispiel behoben.
Sharif
1
Kann verfeinert werden als(0 until (jsonArray.length()))
Jimit Patel
1
for (i in 0 until jsonArray.length()){
    //do your stuff
    }
VaibhavNalawade
quelle
1
Können Sie uns etwas mehr erklären?
Dieter Meemken
2
Während dieser Code die Frage lösen kann, einschließlich einer Erklärung, wie und warum dies das Problem löst, würde dies wirklich dazu beitragen, die Qualität Ihres Beitrags zu verbessern, und wahrscheinlich zu mehr Up-Votes führen. Denken Sie daran, dass Sie in Zukunft die Frage für die Leser beantworten, nicht nur für die Person, die jetzt fragt. Bitte bearbeiten Sie Ihre Antwort, um eine Erklärung hinzuzufügen, und geben Sie an, welche Einschränkungen und Annahmen gelten.
Dave