swift JSON中的有序字典

pgvzfuti  于 2023-04-10  发布在  Swift
关注(0)|答案(6)|浏览(245)

有3个字符串变量

public var userLoginId : String?
public var searchString : String?
public var tableName : String?

我有一本字典:

let dict = ["userLoginId" : userLoginId, "searchString" : searchString,"tableName" : tableName]

现在我用JSON序列化它:

let data =  try! JSONSerialization.data(withJSONObject: dict, options :[])
let jsonstring = String(data:data, encoding:.utf8)!

jsonstring中,每次我得到一个无序的JSON如下:

"{\"tableName\":\"null\",\"userLoginId\":\"Dilip\",\"searchString\":\"Tata\"}"

我怎样才能得到与我给dictionary赋值相同的格式?

yizd12fk

yizd12fk1#

Dictionaries无序的
但是💡!
因为**JSON是一个String,所以可以有一个有序的JSON。你可以使用this library**来按照原来的顺序解析JSON。用法很简单:

try JSON.parse(string: jsonString)

排序字典

iOS 11macOS 10.13开始,JSONSerialization有一个新的选项用于排序键,您可以用途:

JSONSerialization.data(withJSONObject: json, options: [.sortedKeys])
kjthegm6

kjthegm62#

Swift的Dictionary不仅没有排序,而且JSON字典也没有,按照标准。你能做的最好的事情就是将键以正确的顺序存储在一个数组中。你不是迭代字典,而是迭代有序的键数组,然后用这些键从字典中获取。
为了避免手动重复键,可以将字典表示为(Key, Value)元组数组,如下所示:

let keyValuePairs = [
    ("userLoginId", userLoginId),
    ("searchString", searchString),
    ("tableName", tableName)
]

let dict = Dictionary(uniqueKeysWithValues: keyValuePairs)
let orderedKeys = keyValuePairs.map { $0.0 }

现在你可以在Swift代码中使用orderedKeys,或者将它们与dict一起存储在JSON中:

print("Example usage:")
for key in orderedKeys {
    let value = dict[key]!
    
    print("\(key): \(value)")
}
bf1o4zei

bf1o4zei3#

我知道一年前有人问过这个问题。但我最近在编写单元测试时遇到了这个问题。基本上,我编写了一个模拟JSON字典,使用JSONSerialization将其转换为数据,并将其传递给一个排序的解析对象。然而,在这个特定的测试中,必须保持顺序,否则测试将失败。而前面描述的方法没有做到这一点。所以对我来说,有效的方法不是从字典开始,而是从测试JSON字符串开始,并使用utf8将其编码为数据。当它被解析为字典时,JSON字符串的顺序在解析的字典中维护。

t3irkdon

t3irkdon4#

字典是“无序集合”。它们的键/值对没有任何顺序。句号。

如果你想要一个有序的集合,使用字典以外的东西。(一个单项字典数组是一种方法。)你也可以编写代码,将字典的键加载到一个可变数组中,对数组进行排序,然后使用排序后的键数组以所需的顺序获取键/值对。
你也可以创建自己的集合类型,它使用字符串作为索引,并按排序顺序保存条目。Swift使这一点变得简单,尽管计算代价很高。

nkoocmlb

nkoocmlb5#

这个问题所称的“字典”实际上是JSON术语中的“对象”。
直接引用权威来源(https://www.json.org/json-en.html):
“对象是一组无序的名称/值对。”
所以,是的,将JSON“字典”视为有序的并不包含在标准中。
但是,我发现这在往返类型的应用程序中很有用:如果你需要以编程方式修改用户提供的JSON文件中的某些值,你通常希望保持整个JSON“布局”。
正如上面的答案所暗示的,多个JSON解析库支持这种行为。
要添加到知识库,请执行以下操作:在Python中,我已经成功地使用了默认的json库,并且发现它 * 确实 * 维护了“dictionaries”=“objects”的项排序。所以我可以做如下的事情,并且可以放心,我将按照原始JSON文件中列出的顺序处理所有键:

import json
with open(fn) as json_file:
    data = json.load(json_file)
for regid, val in data["registers"].items():
    logging.info(f"Processing {regid} with value {val}...")

对应的示例JSON文件:

{
   "registers": {
      "volume": 16.0,
      "brightness": 0.5
    }
}
g6ll5ycj

g6ll5ycj6#

设计思路是通过脚本修改原始JSON,在每个项目前加上编号。在Swift中读取JSON后,按照编号排序。
设计思路是通过脚本修改原JSON在每一项前面加一个数字,然后在Swift中根据增加的数字对JSON进行排序。
我们通过Python脚本来为JSON添加编号:
我们使用Python脚本向JSON添加数字:

import json
import os
# Change the current working directory to the directory where the script is located
os.chdir(os.path.dirname(os.path.abspath(__file__)))

# Read the file
with open("RSSSourceGPT.json", "r") as f:
    data = json.load(f)

# Create a copy
data_copy = data.copy()

# Add index in front of the keys
for i, key in enumerate(data.keys()):
    new_key = str(i) + "_" + key
    data_copy[new_key] = data_copy.pop(key)

# Save the copy
with open("RSSSourceGPT_copy.json", "w") as f:
    json.dump(data_copy, f)

然后在Swift中,我们读取JSON:

let unsortedJSON = try JSONSerialization......//complete the code

然后按原始顺序对源进行排序:

let sortedSources = sources.sorted(by: { (source1, source2) -> Bool in
    if let index1 = Int(source1.name.components(separatedBy: "_").first ?? ""),
       let index2 = Int(source2.name.components(separatedBy: "_").first ?? "") {
        return index1 < index2
    }
    return false
})

最后,从每个键名中删除索引标签:

let sourcesWithoutIndex = sources.map { (source) -> RSSSourceGPT in
    let nameWithoutIndex = source.name.components(separatedBy: "_").count > 1 ?
        source.name.components(separatedBy: "_")[1] : source.name
    return RSSSourceGPT(id: source.id, name: nameWithoutIndex, desc: source.desc)
}

相关问题