根据条件从 JSON 获取值

Get Values from JSON According to Condition

我在应用程序包中有一个本地 Json 文件。

现有 Json 文件:

[
    {
        "id": 1001,
        "key1": true,
        "key2": "key2Value",
    },
    {
        "id": 1002,
        "key1": false,
        "key2": "key2Value",
    },
    {
        "id": 1003,
        "key1": true,
        "key2": "key2Value",
    },
]

如果 key1 值为 true,我想遍历 json 并获取 ID。

我这样试过,但出现错误:

let vehicleInfoTest: [Vehicle] = readJSONTest("vehicleInfo.json")
func readJSONTest<T: Codable>(_ named: String) -> T{
    let data: Data
    let ids: Int
    do {
        let fileURL = try FileManager.default
            .url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
            .appendingPathComponent("vehicleInfo.json")

        data = try Data(contentsOf: fileURL)
        
        // I can successfully get the foo
        let foo = try JSONDecoder().decode(T.self, from: data)
        
        // For loop gives an error: For-in loop requires 'Vehicle' to conform to 'Sequence'
        for item in foo as! Vehicle{
            if item.key1 == true{
                    ids = item.id
                }
        }
        return foo
    } catch {
        fatalError("Couldn't find  in main bundle.")
    }
}

最后ids应该是这样的:

ids = 1001, 1003

如何获取 ID?

简单

let ids = vehicles.filter { [=10=].key1 }.map { [=10=].id } 

而不是您的 for 循环应该可以解决问题 - 但是,这不应该是通用方法的一部分。

要么 readJSONTest 是通用的,要么它知道 Vehicle 的内部结构,但实际上不应该两者都做。

此外,当 key1 已经是非可选 Bool 时,请不要说 x.key1 == true

泛型函数中的非泛型代码没有意义。

循环假设T是一个数组并且类型有一个成员key1。在循环外过滤数组,使函数throw

func readJSONTest<T: Decodable>(_ named: String) throws -> T {
    let fileURL = try FileManager.default
        .url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
        .appendingPathComponent("vehicleInfo.json")
    
    let data = try Data(contentsOf: fileURL)
    return try JSONDecoder().decode(T.self, from: data)
    
}
let vehicleInfoTest: [Vehicle] = try readJSONTest("vehicleInfo.json")
let ids = vehicleInfoTest.lazy.filter{[=10=].key1}.map{[=10=].id}

您的代码有点乱,您有一个通用函数,您尝试将其用作非通用函数,并且其中还有一些其他乱七八糟的东西。由于您首先需要在步骤 1 中调用通用函数,然后在第二步中对结果进行过滤,因此以下代码将为您提供 ID,其中 key1 为 true

let vehicleInfoTest: [Vehicle] = readJSONTest("vehicleInfo.json")
let idValues = vehicleInfoTest.filter({ [=10=].key1 }).map( {[=10=].id })

现在要让它工作,需要清理函数

func readJSONTest<T: Codable>(_ named: String) -> T{
    do {
        let fileURL = try FileManager.default
            .url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
            .appendingPathComponent(named). //use parameter, not hardcoded string

        let data = try Data(contentsOf: fileURL)
        return try JSONDecoder().decode(T.self, from: data) // directly return decoded values
    } catch {
        fatalError("Decoding failed with error \(error)") // More useful error message
    }
}