【问题标题】:Kotlin: Iterate through a JSONArrayKotlin:遍历 JSONArray
【发布时间】:2016-07-11 03:01:17
【问题描述】:

我正在使用 Kotlin 和 Realm 编写一个 Android 应用程序。 我有一个 JSONArray,我想遍历这个数组中的 JSONObject,以便将它们加载到 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 库?
  • 我使用org.json.JSONArrayorg.json.JSONObject

标签: android json kotlin


【解决方案1】:

不幸的是,JsonArray 没有公开迭代器。所以你必须使用索引范围来遍历它:

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

    // Your code here
}

【讨论】:

  • 更好的是:for(i in 0 until persons.length())
  • for(i in 0 until persons.length() 肯定更好,因为它似乎有助于避免可怕的一对一问题。但是为什么不暴露迭代器呢?默认情况下这似乎很疯狂……它是一种完全专注于多个对象的核心对象类型。迭代似乎很自然,对吧???
  • 对我帮助很大。谢谢大佬。
  • 我超出范围异常
  • 这是错误的方向......请删除这个错误的答案。声明很容易自己声明一个 iterator() fun 的说法更有帮助!
【解决方案2】:

即使某些类没有公开iterator 方法,您仍然可以通过提供扩展函数iterator 使用for 语句对其进行迭代:

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

现在,当您在 for 语句中使用 JSONArray 时,会调用此扩展来获取迭代器。它创建一系列索引并将每个索引映射到与该索引对应的项目。

我认为转换为JSONObject 是必需的,因为数组不仅可以包含对象,还可以包含基元和其他数组。而asSequence调用就是在这里偷懒执行map操作。

通用方式(假设所有数组条目的类型相同)

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

【讨论】:

  • 谢谢伊利亚。作为一名 Kotlin 新手,我很感激我能得到的每一个意见。
  • 我更喜欢这个解决方案,因为它更好地利用了 Kotlin 的特定功能
  • 当然你不会总是有一个 JSONObject 数组。你可能想试试:operator fun &lt;T&gt; JSONArray.iterator(): Iterator&lt;T&gt; = (0 until length()).asSequence().map { get(it) as T }.iterator() 现在它当然有一个“未经检查的演员表”。
  • 如果数组为空,@Sevastyan 0 until length() 将产生一个空范围,因此 get 将在空范围的元素上被调用 0 次(即根本不会被调用)。
  • @Sevastyan 你可以用try.kotlinlang.org快速检查0 until 0的结果
【解决方案3】:

怎么样

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

?

【讨论】:

  • jsonArray.getJSONObject(r) 应该是 jsonArray.getJSONObject(i) 还是我误解了什么?
  • 是的,你是对的,应该是i 而不是r。固定代码示例。
  • 可以细化为(0 until (jsonArray.length()))
  • 感谢您提供答案。您能否编辑您的答案以包括对您的代码的解释?
【解决方案4】:
for (i in 0 until jsonArray.length()){
    //do your stuff
    }

【讨论】:

  • 你能再解释一下吗?
  • 虽然此代码可以解决问题,including an explanation 说明如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提出问题的人。请edit您的答案添加解释,并说明适用的限制和假设。
【解决方案5】:

最短的方法是:

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

基本上从 0 到 jsonarray 长度的范围,它每次取一个数字并将其用作检索当前对象的索引

【讨论】:

  • 感谢您提供答案。您能否编辑您的答案以包括对您的代码的解释?这将有助于未来的读者更好地了解正在发生的事情,尤其是那些刚接触该语言并难以理解概念的社区成员。
  • 感谢您提供答案。您能否编辑您的答案以包括对您的代码的解释?
猜你喜欢
  • 2011-10-05
  • 1970-01-01
  • 1970-01-01
  • 2019-10-20
  • 2020-08-23
  • 2017-10-28
  • 1970-01-01
  • 2011-06-14
  • 2019-07-30
相关资源
最近更新 更多