Котлін: Ітерація через JSONArray


79

Я пишу додаток для Android, використовуючи Kotlin і Realm. У мене є JSONArray, і я хочу переглядати JSONObjects у цьому масиві, щоб завантажити їх у клас бази даних Realm:

Клас царства:

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

}

JSONArray:

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

Я спробував повторити наступне:

for (item : JSONObject in persons) {

}

... але я отримую for-loop range must have an iterator() methodпомилку.


Яку бібліотеку JSON ви використовуєте?
mfulton26,

Я використовую org.json.JSONArrayі org.json.JSONObject.
Амбран

Відповіді:


152

На жаль, JsonArrayне виставляє ітератор. Тож вам доведеться перебирати його за допомогою діапазону індексів:

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

    // Your code here
}

43
Приємніше: for (i in 0 until persons.length ())
Pointer Null

8
for(i in 0 until persons.length()безумовно приємніше, оскільки, здається, допомагає уникнути страшної непоодинокої проблеми. Але чому б ітератору не викрити? За замовчуванням це здається божевільним ... це основний тип об’єкта, який повністю зосереджений на декількох об’єктах. Ітерація через здається цілком природною, правда ???
Майк Вільямсон

Мені це дуже допомагає. Дякую товаришу.
marcode_ely

1
я вийшов за межі винятків
famfamfam

41

Навіть якщо якийсь клас не виставляє iteratorметод, ви все одно можете повторити його за допомогою forоператора, надавши функцію розширення iterator:

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

Тепер, коли ви використовуєте JSONArrayв forінструкції, це розширення викликається, щоб отримати ітератор. Він створює діапазон індексів і відображає кожен індекс до елемента, що відповідає цьому індексу.

Я припускаю, що приведення JSONObjectпотрібно, оскільки масив може містити не тільки об'єкти, але також примітиви та інші масиви. І asSequenceзаклик тут виконати mapоперацію ліниво.

Загальний спосіб ( припускаючи, що всі записи масиву однакові)

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

3
Дякую Ілля. Як новачок Kotlin, я ціную кожен внесок, який я можу отримати.
Амбран

1
Я віддаю перевагу цьому рішенню, оскільки воно використовує більші переваги специфічної функціональності
Котліна

2
Хоча, звичайно, у вас не завжди буде масив JSONObject. Можливо, ви захочете спробувати: operator fun <T> JSONArray.iterator(): Iterator<T> = (0 until length()).asSequence().map { get(it) as T }.iterator()тепер у нього, звичайно, "невстановлений акторський склад".
androidguy

1
@Sevastyan 0 until length()видасть порожній діапазон, якщо масив порожній, тому getбуде викликаний 0 разів (тобто не буде викликатися взагалі) для елементів порожнього діапазону.
Ілля

2
@Sevastyan, ти можеш швидко перевірити те, що 0 until 0оцінює, за допомогою try.kotlinlang.org
Ілля

3

Як щодо

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

?


jsonArray.getJSONObject(r)повинно бути, jsonArray.getJSONObject(i)чи я щось неправильно зрозумів?
Амбран

так, ви праві, це повинно бути iНЕ r. Приклад фіксованого коду.
Шариф

1
Можна уточнити як(0 until (jsonArray.length()))
Jimit Patel

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

1
Ви можете пояснити трохи більше?
Дітер Меемкен

2
Хоча цей код може вирішити питання, включаючи пояснення того, як і чому це вирішує проблему, насправді допомогло б поліпшити якість вашої публікації, і, можливо, призведе до більшої кількості голосів. Пам’ятайте, що ви відповідаєте на запитання читачам у майбутньому, а не лише тому, хто задає зараз. Будь ласка, відредагуйте свою відповідь, щоб додати пояснення, та вкажіть, які обмеження та припущення застосовуються.
Дейв

0

Найкоротший шлях:

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

В основному від діапазону, що від нуля до довжини jsonarray, потрібно одне число за раз і використовувати його як індекс для отримання поточного об'єкта


Дякуємо, що надали відповідь. Будь ласка, відредагуйте свою відповідь, щоб включити пояснення вашого коду? Це допоможе майбутнім читачам краще зрозуміти, що відбувається, і особливо тим членам спільноти, хто новачок у мові та намагається зрозуміти поняття.
Jeremy Caney
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.