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

Swift - Stored values order is completely changed in Dictionary

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

//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行中获取的。为什么会这样??

来自The Swift Programming Language

A dictionary stores associations between keys of the same type and values of the same type in an collection with no defined ordering.

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

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

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


let sorted = myDictionary.sorted {[=10=].key < .key}  // or {[=10=].value < .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)" )
}

这是因为字典的定义:

词典

A dictionary stores associations between keys of the same type and values of the same type in an collection with no defined ordering.

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


编辑:

NSDictionary

Dictionaries Collect Key-Value Pairs. Rather than simply maintaining an ordered or unordered collection of objects, an NSDictionary stores objects against given keys, which can then be used for retrieval.

顺序,但是为了调试目的在打印时有排序。

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

来自 -[NSDictionary description] 的文档:

If each key in the dictionary is an NSString object, the entries are listed in ascending order by key, otherwise the order in which the entries are listed is undefined. This property is intended to produce readable output for debugging purposes, not for serializing data.

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

OrderedDictionary is a lightweight implementation of an ordered dictionary data structure in Swift.

The OrderedDictionary structure is an immutable generic collection which combines the features of Dictionary and Array from the Swift standard library. Like Dictionary it stores key-value pairs and maps each key to a value. Like Array it stores those pairs sorted and accessible by a zero-based integer index.

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

晚会有点晚了,但是如果你想维持秩序那就用KeyValuePairs,这里的trade-off是如果你用KeyValuePairs你就失去了维持秩序的能力列表中的独特元素

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

打印

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

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

来自Dictionaries (Swift Standard Library documentation)

A dictionary is a type of hash table, providing fast access to the entries it contains. Each entry in the table is identified using its key, which is a hashable type such as a string or number. You use that key to retrieve the corresponding value, which can be any object. In other languages, similar data types are known as hashes or associated arrays.

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


不用字典存储关联数据

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

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

如果你想找到水果的颜色,你必须遍历每个元素并检查它的水果值,然后 return 颜色部分。

字典使用 hash functions to store their data using a unique hash that represents the key that is being stored. For swift this means turning our key—in this case a String—into an Int. Swift uses Int-based hashes, which we know because we all read the Hashable protocol documentation 优化其存储,我们看到 Hashable 定义了 hashValue 属性,return 是 Int


用字典存储关联数据

使用字典的好处是您可以快速读取和写入数据;它使 "looking up" 关联数据变得简单快捷。通常 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 空间是为以后可能出现的更多值保留的,但这也是为什么当我们尝试从字典中获取值时,它们可能为零。因此,当我们决定添加更多值时,例如:

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 值,为我们的实际存储机制提供了有效的数组索引,一个数组,它对世界是隐藏的。


我敢肯定这比你想要的要多,而且可能有很多不准确的地方,但它给了你字典在实践中如何工作的要点,希望听起来比 "that's just how it works."

在搜索 Swift 词典的实际性能时, 提供了一些额外的相关细节。

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

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

希望对您有所帮助!

✅ 有可能!

虽然Dictionary没有排序,但你可以使用官方的OrderedDictionary让它保留初始顺序Swift Repo

已排序的合集目前包含:

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