Котлін: Ітерація через 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.