当前位置: 首页 > 面试题库 >

仅在运行时知道键时展平JSON

微生景胜
2023-03-14
问题内容

假设我们有一个类似以下的JSON结构(通常在Firebase的实时数据库中使用):

{
  "18348b9b-9a49-4e04-ac35-37e38a8db1e2": {
    "isActive": false,
    "age": 29,
    "company": "BALOOBA"
  },
  "20aca96e-663a-493c-8e9b-cb7b8272f817": {
    "isActive": false,
    "age": 39,
    "company": "QUONATA"
  },
  "bd0c389b-2736-481a-9cf0-170600d36b6d": {
    "isActive": false,
    "age": 35,
    "company": "EARTHMARK"
  }
}

使用Decodable我想将其转换为3个元素的数组:

struct BoringEntity: Decodable {
    let id: String
    let isActive: Bool
    let age: Int
    let company: String

    init(from decoder: Decoder) throws {
        // ...
    }
}

let entities: [BoringEntity] = try! JSONDecoder()...

ID 属性对应于JSON对象的根弦,例如:18348b9b-9a49-4e04-ac35-37e38a8db1e2

解决方法:

我已经尝试了几种方法,但是在不需要辅助实体(或使用可选对象)的情况下无法获得id属性:

/// Incomplete BoringEntity version to make Decodable conformance possible.
struct BoringEntityIncomplete: Decodable {
    let isActive: Bool
    let age: Int
    let company: String
}

// Decode to aux struct
let decoded = try! JSONDecoder().decode([String : BoringEntityIncomplete].self, for: jsonData)
// Map aux entities to BoringEntity
let entities = decoded.map { BoringEntity(...) }

使用init(from: Decoder)不像其他情况那么简单,因为keyedContainer(,)由于密钥未知,因此无法使用。

Decodable不适合于这些类型的案件?


问题答案:

基础实体:

struct BoringEntity: Decodable {
    let id: String
    let isActive: Bool
    let age: Int
    let company: String
}

解决方案1:使用没有密钥的额外结构

/// Incomplete BoringEntity version to make Decodable conformance possible.
private struct BoringEntityBare: Decodable {
    let isActive: Bool
    let age: Int
    let company: String
}

// Decode to aux struct
private let decoded = try! JSONDecoder().decode([String : BoringEntityBare].self, from: jsonData)
// Map aux entities to BoringEntity
let entities = decoded.map { BoringEntity(id: $0.key, isActive: $0.value.isActive, age: $0.value.age, company: $0.value.company) }
print(entities)

解决方案2:使用包装器

多亏了Code Different,我得以将自己的方法与他的PhantomKeys想法结合起来,但是却无法解决:必须始终使用额外的实体。

struct BoringEntities: Decodable {
    var entities = [BoringEntity]()

    // This really is just a stand-in to make the compiler happy.
    // It doesn't actually do anything.
    private struct PhantomKeys: CodingKey {
        var intValue: Int?
        var stringValue: String
        init?(intValue: Int) { self.intValue = intValue; self.stringValue = "\(intValue)" }
        init?(stringValue: String) { self.stringValue = stringValue }
    }

    private enum BareKeys: String, CodingKey {
        case isActive, age, company
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: PhantomKeys.self)

        // There's only one key
        for key in container.allKeys {
            let aux = try container.nestedContainer(keyedBy: BareKeys.self, forKey: key)

            let age = try aux.decode(Int.self, forKey: .age)
            let company = try aux.decode(String.self, forKey: .company)
            let isActive = try aux.decode(Bool.self, forKey: .isActive)

            let entity = BoringEntity(id: key.stringValue, isActive: isActive, age: age, company: company)
            entities.append(entity)
        }
    }
}

let entities = try JSONDecoder().decode(BoringEntities.self, from: jsonData).entities
print(entities)


 类似资料:
  • 问题内容: 所以对于这个项目,我试图在运行时扩展一个类。我想知道,这有可能吗?如果是这样,我该怎么办?是否有用于这些目的的库? 问题答案: CGLib是您要查找的库。它在扩展类或在运行时实现接口方面非常强大,因此许多流行的框架(如Spring或Hibernate)都使用它。 您可以使用以下代码创建类扩展 尽管您可能会使用具有所需逻辑的有用的方法拦截器替换回调。

  • 问题内容: 我有能力在编译时扩展一个类,但是我需要能够在运行时使用已实例化的超类的实例创建此子类的实例。 从理论上讲这应该是可能的,因为已经在子类构造函数之前调用了超类构造函数。 我没有足够的程序访问权限来更改实例化到我的子类或中断原始实例化。 用例:现有一个类X实例的数组。我的代码在之后加载。我需要使用已加载的子类Y扩展X来覆盖实例X之一的方法之一。父程序仅通过该数组访问对象,因此我想用Y实例替

  • 苏,希望你们都没事。出于某种原因,在我的java代码中,当我按下一个键(当它工作时),我的ActionListener要求我保持计时器启动,否则会绘制一个矩形并显示JLabel simple的条件不会运行,因为ActionListener无法调用它。 这是工作代码。 下面是使actionEvent不执行的原因

  • 在Android中有没有可能只在状态栏展开时才显示通知?我的意思是,只有当我拖动状态栏,我可以看到通知,否则它将被隐藏。如果有可能,我如何实施它?我只需要在最小视图中隐藏状态栏中的应用程序图标

  • 所以我昨天从Gulp4.0开始,所以当我开始gulp时,他只在第一次运行时将我的sass编译成css。为什么这是我的 [22:36:57]正在启动“监视任务”...

  • 有没有办法知道Val的值在编译时或运行时是已知的?我是说我能在IDE或其他地方查一下吗?自从我用谷歌搜索之后,就再也没有关于它的文章了。他们只是指出哪些是在编译时已知的,哪些是在运行时已知的,但没有提到如何知道这一点。 据我所知,如果我将一个基元类型或字符串赋给Val,它的值在编译时就会被知道。相反,如果我指定了一个函数或对象(需要从另一个地方计算或引用该值),它的值在运行时是已知的。但是,有没有