gpt4 book ai didi

ios - 如何 json 解码链接的相关项目?

转载 作者:行者123 更新时间:2023-11-28 10:26:55 25 4
gpt4 key购买 nike

让我们假设这个表示多语言单词的 json:

[{
"id": "en_cat",
"name": "cat",
"def": "A cat is a domestic animal of the feline family.",
"trans": {
"fr": "fr_chat",
"ru": "ru_ко́шка"
}
}, {
"id": "fr_chat",
"name": "chat",
"def": "Le chat est un animal domestique de la famille des félins.",
"trans": {
"en": "en_cat",
"ru": "ru_ко́шка"
}
}, {
"id": "ru_ко́шка",
"name": "ко́шка",
"def": "..."
"trans": {
"en": "en_cat",
"fr": "fr_chat"
}
}]

此 json 在“trans”(翻译)嵌套容器中具有彼此相关的项目。

我的课很简单

class Word: Decodable {
var id: String
var name: String
var definition: String
var enTranslation: Word?
var frTranslation: Word?
var ruTranslation: Word?

enum JsonCodingKey: String, CodingKey {
case id
case name
case def
case trans
}

enum JsonTransCodingKey: String, CodingKey {
case en
case fr
case ru
}

convenience init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: JsonCodingKey.self)
let id = try container.decode(String.self, forKey: .id)
let name = try container.decode(String.self, forKey: .name)
let definition = try container.decode(String.self, forKey: .def)
self.init(id: id, name: name, definition: definition)

// Tricky part here...
let transContainer = try container.nestedContainer(keyedBy: JsonTransCodingKey.self, forKey: .trans)
if let en = transContainer.decode(String.self, forKey: .en) {
self.enTranslation = realm.find(wordId: en) // Singleton that looks into memory for the word
}
// And repeat the same if logic for the other languages...
}
}

JSON 解码最快的 (CPU) 方式是什么?

我的处理方式“感觉”不对:

  1. 我解码单词使用
let jsonDecoder = JSONDecoder()
let words = jsonDecoder.decode([Word].self, from: data)

但是这些词没有任何翻译链接,因为它们在实时解析过程中不“已知”。

在我的示例中,当我们解析第一个单词“cat”时,我们仍然不知道法语和俄语单词。

  1. 所以我必须再次解码,一旦我记住了所有单词。
let jsonDecoder = JSONDecoder()
let words = jsonDecoder.decode([Word].self, from: data) // Words don't have their translations
self.saveInMemory(words) // In my case, it is saved to Realm.
let words = jsonDecoder.decode([Word].self, from: data)
/* Words are now linked to each others
Because during decoding, the func Word.init(from decoder) will
look into `Realm` and find the translations. */

这种双重解码感觉有点矫枉过正。反正没有直接查json数据的吗?

最佳答案

先解码,再生成结构。您正试图将这两者结合起来,这是没有意义的。

您的第一次解码执行实际解码,您的第二次解码仅执行链接。

取而代之的是,解码为临时结构,构建标识符字典并使用它来将它们链接到最终对象。

老实说,没有必要做实际的链接。它仍然可以是完全动态的,使用字典。

一种可能的方法:

let data = """
[{
"id": "en_cat",
"name": "cat",
"def": "A cat is a domestic animal of the feline family.",
"trans": {
"fr": "fr_chat",
"ru": "ru_ко́шка"
}
}, {
"id": "fr_chat",
"name": "chat",
"def": "Le chat est un animal domestique de la famille des félins.",
"trans": {
"en": "en_cat",
"ru": "ru_ко́шка"
}
}, {
"id": "ru_ко́шка",
"name": "ко́шка",
"def": "...",
"trans": {
"en": "en_cat",
"fr": "fr_chat"
}
}]
""".data(using: .utf8)!

enum Language: String {
case english = "en"
case french = "fr"
case russian = "ru"
}

class Word: Decodable {
let id: String
let name: String
let definition: String
let translationsIds: [String: String]

weak var parentDictionary: Dictionary!

private enum CodingKeys: String, CodingKey {
case id
case name
case definition = "def"
case translationsIds = "trans"
}

func translation(for language: Language) -> Word? {
return translationsIds[language.rawValue].flatMap { parentDictionary.words[$0] }
}
}

class Dictionary: Decodable {
let words: [String: Word]

required init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let words = try container.decode([Word].self)
self.words = [String: Word](uniqueKeysWithValues: words.map { (key: $0.id, value: $0) })

for word in words {
word.parentDictionary = self
}
}
}

let decoder = JSONDecoder()
let dictionary = try decoder.decode(Dictionary.self, from: data)

print(dictionary.words["fr_chat"]?.translation(for: .english)?.name)

关于ios - 如何 json 解码链接的相关项目?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58804423/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com