Swift - 字典中的存储值顺序完全改变

Posted

技术标签:

【中文标题】Swift - 字典中的存储值顺序完全改变【英文标题】:Swift - Stored values order is completely changed in Dictionary 【发布时间】:2015-06-18 12:45:17 【问题描述】:

我试图显示字典格式的数据。下面,有三个尝试。第一次尝试,输出顺序完全改变。第二次尝试,输出顺序与输入相同。但是,在第三次尝试中,我将变量声明为 NSDictionary。我收到的确切输出。为什么字典会发生这种变化?请指导我。我搜索了 Swift 的 Dictionary 标签。但我没找到。

//First Attempt
var dict : Dictionary = ["name1" : "Loy", "name2" : "Roy"]
        println(dict)

//output:
[name2: Roy, name1: Loy]

//Second Attempt
var dict : Dictionary = ["name2" : "Loy", "name1" : "Roy"]
        println(dict)

//output:
[name2: Loy, name1: Roy]
-----------------------------------------------------------

//Third Attempt With NSDictionary
var dict : NSDictionary = ["name1" : "Loy", "name2" : "Roy"]
            println(dict)

//output:

    name1 = Loy;
    name2 = Roy;

另一个问题:我已使用游乐场进行验证。我的屏幕截图如下:

这里,在 NSDictionary 中,我将 name5 作为第一个,但在右侧显示 name2,然后,在 println 中,它以升序显示。为什么会这样??

在这里,在 Dictionary 中,我首先给出了 name5,但在右侧显示 name2,然后在 println 中显示,它是如何在 Dictionary 行中获取的。为什么会这样??

【问题讨论】:

您无法对字典进行排序。你需要一个元组数组 我没有排序。我在问,为什么这个输出会改变? 它永远不会按照您输入数据的方式排列 但是,在 NSDictionary....???为什么它的排列方式与输入相同? 我再次编辑了我的问题。 【参考方案1】:

来自The Swift Programming Language:

字典将同一类型的键和同一类型的值之间的关联存储在一个集合中,没有定义顺序

基本上,输出中的项目顺序是任意的,取决于数据结构的内部实现,不应依赖。

【讨论】:

【参考方案2】:

您不能对字典进行排序,但可以对其键进行排序并按如下方式循环遍历它们:

let myDictionary = ["name1" : "Loy", "name2" : "Roy", "name3" : "Tim", "name4" : "Steve"]   // ["name1": "Loy", "name2": "Roy", "name3": "Tim", "name4": "Steve"]


let sorted = myDictionary.sorted $0.key < $1.key  // or $0.value < $1.value to sort using the dictionary values
print(sorted) // "[(key: "name1", value: "Loy"), (key: "name2", value: "Roy"), (key: "name3", value: "Tim"), (key: "name4", value: "Steve")]\n"
for element in sorted 
    print("Key = \(element.key) Value = \(element.value)" )

【讨论】:

最后,字典不会按定义的顺序存储。 NSDictionary 将以定义的顺序存储。对吗??? 我正在对键进行排序。字典永远不会被整理 @McDonal_11 字典是一组无序的键值对。 NSDictionary 是键值对的有序数组。 NSDictionary 不是有序数组。它是无序的。【参考方案3】:

这是因为字典的定义:

字典

字典将相同类型的键和相同类型的值之间的关联存储在没有定义排序的集合中。

没有没有顺序,它们的输出可能与输入时不同。这与 NSSet 相当。


编辑:

NSDictionary

​​>

字典收集键值对。 NSDictionary 不是简单地维护有序或无序的对象集合,而是根据给定的键存储对象,然后可以将其用于检索。

也有 没有顺序,但是出于调试目的,打印时有排序。

【讨论】:

如何在评论中发布图片??我有屏幕截图,它会清楚地解释我的疑问吗? @McDonal_11 let nsdict = NSDictionary(objects: ["bob", "ron", "roy", "jon"], forKeys: ["name4", "name6", "name1", "name2"]) Swift::Dictionary 和 NSDictionary 都是无序的。 NSDictionary 甚至“大部分”都不维护任何顺序。实现完全无序。【参考方案4】:

NSDictionarySwift::Dictionary 都没有订购它的存储空间。不同之处在于某些NSDictionary 对象在打印时对其输出进行排序,而Swift::Dictionary 则不会。

来自-[NSDictionary description]的文档:

如果字典中的每个键都是一个 NSString 对象,则条目是 按键按升序排列,否则按 列出的条目未定义。此属性旨在产生 用于调试目的的可读输出,而不是用于序列化数据。

【讨论】:

我的立场是正确的。奇怪的是,我从来没有依赖过订单,但从来没有出现过故障。对我来说很奇怪......我一直都知道它不会被订购,但有趣的是 ios 并没有像这样迅速地洗牌。我会为知名度投票。 @op 最好的方法可能是使用数组来跟踪。 如果您遍历字典的内容,您几乎肯定会看到不同的顺序。 println() 调用 -[NSDictionary description] 方法执行排序,但其他字典操作不这样做。【参考方案5】:

这确实是字典的问题。但是,有一个库可用于确保订单保持您初始化的方式。

OrderedDictionary 是 Swift 中有序字典数据结构的轻量级实现。

OrderedDictionary 结构是一个不可变的泛型集合,它结合了 Swift 标准库中 Dictionary 和 Array 的特性。与 Dictionary 一样,它存储键值对并将每个键映射到一个值。与 Array 一样,它存储那些按从零开始的整数索引排序和访问的对。

在这里查看: https://github.com/lukaskubanek/OrderedDictionary

【讨论】:

【参考方案6】:

聚会有点晚了,但如果你想保持秩序,那么使用KeyValuePairs,这里的权衡是如果你使用KeyValuePairs,你将失去在你的列表中维护独特元素的能力

var user: KeyValuePairs<String, String> 
    return ["FirstName": "NSDumb",
            "Address": "some address value here",
            "Age":"30"]

打印

["FirstName": "NSDumb", "Address": "some address value", "Age": "30"]

【讨论】:

你好@NSDumb 可以在其中添加动态数据,就像我们在字典中所做的那样,例如:arr["name"] = someData_From_WS. 晚一点仍然有助于加载!我遇到了这个问题,我一直在想为什么我的代码上的顺序会发生变化,感谢分享页面,它有很大帮助。【参考方案7】:

字典本质上不是为了排序而设计的,这意味着它们不应该是有序的(尽管它们可以是!)。

来自Dictionaries (Swift Standard Library documentation):

字典是一种哈希表,可以快速访问其中包含的条目。表中的每个条目都使用其键标识,键是可散列的类型,例如字符串或数字。您使用该键来检索相应的值,该值可以是任何对象。在其他语言中,类似的数据类型称为哈希或关联数组。

这需要一些数据结构的基本知识,我将简要概述和过度简化。


在没有字典的情况下存储关联数据

考虑一下,如果没有字典,而您不得不使用元组数组来存储有关不同水果及其颜色的一些信息,就像另一个答案所建议的那样:

let array = [
   ("Apple", "Red"),
   ("Banana", "Yellow"),
   // ...
]

如果您想找到水果的颜色,您必须遍历每个元素并检查其值是否为水果,然后返回颜色部分。

字典使用 hash functions 优化其存储,以使用表示正在存储的键的唯一 hash 存储其数据。对于 swift,这意味着将我们的密钥(在本例中为 String)转换为 Int。 Swift 使用基于Int 的哈希,我们知道这是因为我们都读过Hashable protocol documentation,并且我们看到Hashable 定义了一个hashValue 属性,该属性返回一个Int


用字典存储相关数据

使用字典的好处是您可以快速读取和写入数据;它使“查找”相关数据变得简单快捷。通常为 O(1) 时间复杂度,虽然苹果文档没有指定,可能是因为它取决于键类型的哈希函数实现。

let dictionary = [
  "Apple": "Red",
  "Banana": "Yellow"
  // ...
]

权衡是订单通常不能保证被保留。 不保证意味着你可能会很幸运,它可能是相同的顺序,但它不是故意的,所以不要依赖它。

作为一个任意的例子,也许字符串"Banana" 被散列成数字0,而"Apple" 变成4。由于我们现在有一个Int,我们可以在底层将我们的字典表示为一个大小为 5 的数组:

// what things *might* look like under, the hood, not our actual code
// comments represent the array index numbers
let privateArrayImplementationOfDictionary = [
  "Yellow",  // 0
  nil,       // 1
  nil,       // 2
  nil,       // 3
  "Red",     // 4
]            // count = 5

您会注意到,我们已将键转换为数组索引,并且有一堆空白处我们什么都没有。由于我们使用的是数组,因此我们可以快速插入数据,并以同样快的速度检索数据。

那些nil 空格是为以后可能出现的更多值保留的,但这也是为什么当我们尝试从字典中获取值时,它们可能为 nil。因此,当我们决定添加更多值时,例如:

dictionary["Lime"] = "Green"        // pretend hashValue: 2
dictionary["Dragonfruit"] = "Pink"  // pretend hashValue: 1

我们的字典在底层可能如下所示:

// what things *might* look like under, the hood, not our actual code
// comments represent the array index numbers
let privateArrayImplementationOfDictionary = [
  "Yellow",  // 0 ("Banana")
  "Pink",    // 1 ("Dragonfruit")
  "Green",   // 2 ("Lime")
  nil,       // 3 (unused space)
  "Red",     // 4 ("Apple")
]            // count = 5

如您所见,这些值根本没有按照我们输入的顺序存储。事实上,钥匙甚至都不存在。这是因为散列函数已经将我们的键更改为其他东西,一组Int 值,它们为我们的实际存储机制提供有效的数组索引,一个隐藏在世界之外的数组。


我确信这比您想要的信息多,并且可能充满了许多不准确之处,但它为您提供了字典在实践中如何工作的要点,并且希望听起来比“这就是它的工作原理”更好。

在搜索 Swift 词典的实际性能时,Is Swift dictionary ... indexed for performance? ... *** 提供了一些额外的可能相关细节。

如果您仍然有兴趣了解有关这方面的更多详细信息,可以尝试实施自己的词典作为学术练习。我还建议买一本关于数据结构和算法的书,有很多可供选择,不幸的是我没有任何建议给你。

您对该主题的深入了解,您就会越了解为什么要使用一种特定的数据结构而不是另一种。

希望有帮助!

【讨论】:

【参考方案8】:

✅有可能!

Dictionary虽然没有排序,但是你可以使用原Swift Repo

的官方OrderedDictionary使其保持初始顺序>

有序集合当前包含:

Ordered Dictionary(您正在寻找的) Ordered Set

他们说很快会合并到 Swift 的源代码中(参考 WWDC21

【讨论】:

以上是关于Swift - 字典中的存储值顺序完全改变的主要内容,如果未能解决你的问题,请参考以下文章

swift实现遍历嵌套字典并修改其中的值

swift实现遍历嵌套字典并修改其中的值

swift实现遍历嵌套字典并修改其中的值

Swift初见Swift字典

我如何更新我的字典 ios Swift 中的数量值

Swift 字典内的值访问和更改(涉及数组的字典)