Swift:一个有序字典

5

我正在学习Swift并尝试理解字典。我习惯于PHP,其中您可能会编写以下内容...

$dataPoints = Array("A"=>1,"B"=>2,"C"=>3);
foreach($dataPoints as $value) {
    echo($value);
}

在这个例子中,值将按顺序输出 - 1、2、3。
我的Swift代码如下...
var dataPoints: Dictionary<String,Int> = ["A":1,"B":2,"C":3]
for (key, value) in dataPoints {
        print(value)
}

然而,值以意外的顺序出现。有没有什么简单的方法可以保持值的创建顺序,或者说一个Swift字典永远无法排序?

3
SwiftObjective-C 中的 Dictionaries/NSDictionary 不是有序的,但你可以查看这些链接:https://dev59.com/bl8e5IYBdhLWcg3wyMwr 和 https://dev59.com/-V0a5IYBdhLWcg3wsKUK 来了解如何排序。 - sbarow
1
这是一个有序字典的自定义实现:http://timekl.com/blog/2014/06/02/learning-swift-ordered-dictionaries/ - Cheng-Yu Hsu
5个回答

10
正如已经回答的那样,字典的关键在于它没有排序。Swift(和Objective-C)中有三种类型的集合:
数组是一组有序的项目。当项目的顺序很重要时,请使用它。
字典是一组无序的键值对集合。当您想要根据键有效地检索值时,请使用它。
集合是一个无序的、唯一的元素包。当您想要拥有一组唯一的元素而不需要特定顺序时,请使用它。
在您的情况下,似乎排序对您很重要,但您希望存储某种值对。也许您应该考虑使用元组数组:
类似这样的东西,也许。
let dataPoints = [("A", 1), ("B", 2), ("C", 3)]

for (letter, number) in dataPoints {
    print("\(letter), \(number)")
}

输出

A, 1
B, 2
C, 3

或者

如果在创建项目之前您不知道它们的顺序,但是基于键有一种自然排序方式,您可以尝试这样做:

let dict = [
    "A" : 1,
    "B" : 2,
    "C" : 3
]

for key in dict.keys.sort() {
    guard let value = dict[key] else { break }
    print("\(key), \(value)")
}

在这种情况下,您会获得一个带有默认排序顺序的键数组(如果您有其他要求,可以使用不同的排序函数),并根据该排序顺序输出键值。

4

谢谢Guillaume,这非常有用。如果您不介意,我还有几个问题: 1- 如果字典是从JSON字符串创建的,那么您永远无法知道原始顺序吗? 2- 是否有一个好的键/值数据类型可供使用,以便我可以创建一个有序的数组? - Ben
3
1- 这并不改变任何事情,词典从来不会保留顺序。需要注意的是,JSON“词典”也是如此(https://dev59.com/rlrUa4cB1Zd3GeqPl6Zl),它们也没有顺序。2- 根据您的需求,您可以将数据存储到一个结构体或类的数组中,这将保留顺序并具有强类型。 - Guillaume Algis

2

有序字典示例的直接链接:https://github.com/apple/swift-collections/blob/main/Documentation/OrderedDictionary.md - Sentry.co

1

如果有用的话,基于这里的回答和因为我从JSON数据源接收数据,我决定最好的方法是将我的字典转换成一个排序的元组数组。我编写了以下函数:

func dictionary_to_sorted_array(dict:Dictionary<String,Int>) ->Array<(key:String,value:Int)> {
    var tuples: Array<(key:String,value:Int)> = Array()
    let sortedKeys = (dict as NSDictionary).keysSortedByValueUsingSelector("compare:")
    for key in sortedKeys {
        tuples.append((key:key as! String,value:dict[key as! String]!))
    }
    return tuples
}

那么,我可以使用以下代码:
var dataPoints: Dictionary<String,Int> = ["A":1,"B":2,"C":3]
dataPointsArray(dictionary_to_sorted_array(dataPoints))
for dataPoint in dataPointsArray {
    print(dataPoint.value)
}

我在Swift方面还是个新手,如果有人有更快的方法来完成这个任务,那就太好了!


1

从Swift 4开始,您可以使用sorted(by:)来返回字典元素(元组)的排序数组。因此,您问题中的代码变为:

var dataPoints = ["A":1,"B":2,"C":3]

var sortedDataPoints = dataPoints.sorted(by: { $0.value < $1.value })
// [(key: "A", value: 1), (key: "B", value: 2), (key: "C", value: 3)]

for (_, value) in sortedDataPoints {
    print(value)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接