Jojodmo
Jojodmo

Reputation: 23596

Ordered map in Swift

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.

Upvotes: 69

Views: 55692

Answers (13)

Mojtaba Hosseini
Mojtaba Hosseini

Reputation: 119302

You can use the official OrderedDictionary from the original Swift Repo

The ordered collections currently contain:

They said it is going to be merged in the Swift itself soon (in WWDC21)

Upvotes: 5

barola_mes
barola_mes

Reputation: 1640

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)

Upvotes: 22

sweetswift
sweetswift

Reputation: 1

use Dictionary.enumerated()

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"

Upvotes: -7

GetSwifty
GetSwifty

Reputation: 7746

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.

Upvotes: 1

Skoua
Skoua

Reputation: 3603

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.

Upvotes: -3

Jay Zi
Jay Zi

Reputation: 39

    var orderedDictionary = [(key:String, value:String)]()

Upvotes: 1

Deep Parekh
Deep Parekh

Reputation: 445

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 }

Upvotes: 9

coffeecoder
coffeecoder

Reputation: 634

"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

Upvotes: 27

AkademiksQc
AkademiksQc

Reputation: 698

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.

Upvotes: 3

Duncan C
Duncan C

Reputation: 131418

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

Upvotes: 7

enes
enes

Reputation: 329

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:

Upvotes: 2

Mundi
Mundi

Reputation: 80265

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 }

Upvotes: 33

chrisamanse
chrisamanse

Reputation: 4319

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).

Upvotes: 38

Related Questions