Ordered map in Swift
IosSwiftDictionarySwift2Ios Problem Overview
Is there any built-in way to create an ordered map in Swift 2? Arrays [T]
are sorted by the order that objects are appended to it, but dictionaries [K : V]
aren't ordered.
For example
var myArray: [String] = []
myArray.append("val1")
myArray.append("val2")
myArray.append("val3")
//will always print "val1, val2, val3"
print(myArray)
var myDictionary: [String : String] = [:]
myDictionary["key1"] = "val1"
myDictionary["key2"] = "val2"
myDictionary["key3"] = "val3"
//Will print "[key1: val1, key3: val3, key2: val2]"
//instead of "[key1: val1, key2: val2, key3: val3]"
print(myDictionary)
Are there any built-in ways to create an ordered key : value
map that is ordered in the same way that an array is, or will I have to create my own class?
I would like to avoid creating my own class if at all possible, because whatever is included by Swift would most likely be more efficient.
Ios Solutions
Solution 1 - Ios
Just use an array of tuples instead. Sort by whatever you like. All "built-in".
var array = [(name: String, value: String)]()
// add elements
array.sort() { $0.name < $1.name }
// or
array.sort() { $0.0 < $1.0 }
Solution 2 - Ios
You can order them by having keys with type Int
.
var myDictionary: [Int: [String: String]]?
or
var myDictionary: [Int: (String, String)]?
I recommend the first one since it is a more common format (JSON for example).
Solution 3 - Ios
"If you need an ordered collection of key-value pairs and don’t need the fast key lookup that Dictionary provides, see the DictionaryLiteral type for an alternative." - https://developer.apple.com/reference/swift/dictionary
Solution 4 - Ios
You can use KeyValuePairs
,
from documentation:
> Use a KeyValuePairs instance when you need an ordered collection of key-value pairs and don’t require the fast key lookup that the Dictionary type provides.
let pairs: KeyValuePairs = ["john": 1,"ben": 2,"bob": 3,"hans": 4]
print(pairs.first!)
//prints (key: "john", value: 1)
Solution 5 - Ios
if your keys confirm to Comparable, you can create a sorted dictionary from your unsorted dictionary as follows
let sortedDictionary = unsortedDictionary.sorted() { $0.key > $1.key }
Solution 6 - Ios
As Matt says, dictionaries (and sets) are unordered collections in Swift (and in Objective-C). This is by design.
If you want you can create an array of your dictionary's keys and sort that into any order you want, and then use it to fetch items from your dictionary.
NSDictionary
has a method allKeys that gives you all the keys of your dictionary in an array. I seem to remember something similar for Swift Dictionary objects, but I'm not sure. I'm still learning the nuances of Swift.
EDIT:
For Swift Dictionaries it's someDictionary.keys
Solution 7 - Ios
Swift does not include any built-in ordered dictionary capability, and as far as I know, Swift 2 doesn't either
Then you shall create your own. You can check out these tutorials for help:
Solution 8 - Ios
I know i am l8 to the party but did you look into NSMutableOrderedSet ?
https://developer.apple.com/reference/foundation/nsorderedset
> You can use ordered sets as an alternative to arrays when the order of > elements is important and performance in testing whether an object is > contained in the set is a consideration—testing for membership of an > array is slower than testing for membership of a set.
Solution 9 - Ios
You can use the official OrderedDictionary
from the original Swift Repo
The ordered collections currently contain:
- Ordered Dictionary (That you are looking for)
- Ordered Set
They said it is going to be merged in the Swift itself soon (in WWDC21)
Solution 10 - Ios
var orderedDictionary = [(key:String, value:String)]()
Solution 11 - Ios
As others have said, there's no built in support for this type of structure. It's possible they will add an implementation to the standard library at some point, but given it's relatively rare for it to be the best solution in most applications, so I wouldn't hold your breath.
One alternative is the OrderedDictionary project. Since it adheres to BidirectionalCollection
you get most of the same APIs you're probably used to using with other Collection
Types, and it appears to be (currently) reasonably well maintained.
Solution 12 - Ios
Here's what I did, pretty straightforward:
let array = [ ["foo": "bar"],
["foo": "bar"],
["foo": "bar"],
["foo": "bar"],
["foo": "bar"],
["foo": "bar"]
]
// usage
for item in array {
let key = item.keys.first!
let value = item.values.first!
print(key, value)
}
Keys aren't unique as this isn't a Dictionary
but an Array
but you can use the array keys.
Solution 13 - Ios
example:
let dict = [ "foo": 1, "bar": 2, "baz": 3, "hoge": 4, "qux": 5]
for (offset: offset, element: (key: key, value: value)) in dict.enumerated() {
print("\(offset): '\(key)':\(value)")
}
// Prints "0: 'bar':2"
// Prints "1: 'hoge':4"
// Prints "2: 'qux':5"
// Prints "3: 'baz':3"
// Prints "4: 'foo':1"