164

I want to sort a dictionary in Swift. I have a dictionary like:

"A" => Array[]
"Z" => Array[]
"D" => Array[]

etc. I want it to be like

"A" => Array[]
"D" => Array[]
"Z" => Array[]

etc.

I have tried many solutions on SO but no one worked for me. I am using XCode6 Beta 5 and on it some are giving compiler error and some solutions are giving exceptions. So anyone who can post the working copy of dictionary sorting.

Dan Beaulieu
  • 19,406
  • 19
  • 101
  • 135
Aleem Ahmad
  • 2,469
  • 4
  • 24
  • 38
  • 2
    possible duplicate of [Can i sort the NSDictionary on basis of key in Objective-C?](http://stackoverflow.com/questions/3583020/can-i-sort-the-nsdictionary-on-basis-of-key-in-objective-c) – jtbandes Aug 19 '14 at 06:49
  • 10
    You can't sort a dictionary, it's an associative container. If you need a particular order, copy keys into an array, and sort them. Then iterate over the keys, and pull their corresponding values. – Sergey Kalinichenko Aug 19 '14 at 06:51
  • @dasblinkenlight So can you tell me that how to sort an array in swift? – Aleem Ahmad Aug 19 '14 at 06:52
  • @AleemAhmad Take a look at [this answer](http://stackoverflow.com/a/24090641/335858), it has `sortedKeys` function. – Sergey Kalinichenko Aug 19 '14 at 06:58
  • @dasblinkenlight I have tried this but it is giving error on [KeyType] – Aleem Ahmad Aug 19 '14 at 07:00
  • @AleemAhmad That's because you need to replace `KeyType` with the type of the key in your particular dictionary (it looks like you're using strings). – Sergey Kalinichenko Aug 19 '14 at 07:04
  • @dasblinkenlight I have written it like this func sortedKeys(isOrderedBefore:(String,String) -> Bool) -> [String] { var array = Array(self.keys) sort(&array, isOrderedBefore) return array } But it is giving me error on line sort(&array, isOrderedBefore) that "'Key is not a subtype of String'" – Aleem Ahmad Aug 19 '14 at 07:08
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/59562/discussion-between-aleem-ahmad-and-dasblinkenlight). – Aleem Ahmad Aug 19 '14 at 07:16

16 Answers16

199
let dictionary = [
    "A" : [1, 2],
    "Z" : [3, 4],
    "D" : [5, 6]
]

let sortedKeys = Array(dictionary.keys).sorted(<) // ["A", "D", "Z"]

EDIT:

The sorted array from the above code contains keys only, while values have to be retrieved from the original dictionary. However, 'Dictionary' is also a 'CollectionType' of (key, value) pairs and we can use the global 'sorted' function to get a sorted array containg both keys and values, like this:

let sortedKeysAndValues = sorted(dictionary) { $0.0 < $1.0 }
print(sortedKeysAndValues) // [(A, [1, 2]), (D, [5, 6]), (Z, [3, 4])]

EDIT2: The monthly changing Swift syntax currently prefers

let sortedKeys = Array(dictionary.keys).sort(<) // ["A", "D", "Z"]

The global sorted is deprecated.

Joannes
  • 2,569
  • 3
  • 17
  • 39
Ivica M.
  • 4,763
  • 1
  • 23
  • 16
  • 3
    This gives you an array of the keys. The array is lacking the values. You could look up the values from the dictionary, I guess. – StilesCrisis Dec 24 '14 at 18:08
  • 2
    You are right. I've just edited the post to provide a solution for getting an array of (key, value) pairs sorted by keys. Thanks for the comment. – Ivica M. Dec 24 '14 at 18:27
  • @IvicaM. Hello! I understood how I can to sort dictionary by keys, but I don't understand how can I sort array of elements in dictionary. Please help me. For example private var contacts: [(String, [User])] = [] – Alexander Khitev Aug 14 '16 at 11:54
  • 6
    Swift 3 = Array(dictionary.keys).sorted(by: <) – miff Dec 23 '16 at 11:48
  • 11
    As of Swift 4, you can write `let sortedKeys = dictionary.keys.sorted()` – Code Different Mar 27 '18 at 12:47
  • 2
    Since many things get duped here, worth mentioning that there is now OrderedDictionary in swift-collections. https://github.com/apple/swift-collections/blob/main/Documentation/OrderedDictionary.md – Rob Napier Jan 10 '23 at 14:50
139

To be clear, you cannot sort Dictionaries. But you can out put an array, which is sortable.

Swift 2.0

Updated version of Ivica M's answer:

let wordDict = [
     "A" : [1, 2],
     "Z" : [3, 4],
     "D" : [5, 6]
]

let sortedDict = wordDict.sort { $0.0 < $1.0 }
print("\(sortedDict)") // 

Swift 3

wordDict.sorted(by: { $0.0 < $1.0 })
Dan Beaulieu
  • 19,406
  • 19
  • 101
  • 135
  • 38
    this actually returns an array of [(String, [Int])] not a Dictionary – scord Feb 12 '16 at 16:27
  • 4
    realized Dictionaries are unsorted, so it doesnt make much sense to recreate the data type anyway. I ended up just saving an array of sorted keys. – scord Feb 12 '16 at 16:59
  • I get `Binary operator > can not be compared to two `Any` operands. Downcasting doesn't work either – Sean Aug 02 '17 at 03:23
38

In Swift 5, in order to sort Dictionary by KEYS

let sortedYourArray = YOURDICTIONARY.sorted( by: { $0.0 < $1.0 })

In order to sort Dictionary by VALUES

let sortedYourArray = YOURDICTIONARY.sorted( by: { $0.1 < $1.1 })
Abdul Karim Khan
  • 4,256
  • 1
  • 26
  • 30
  • 5
    Note that this return a sorted array of dictionary elements. You can loop on it like it was a dictionary `for (key, value) in sortedDictArray { }` – vomi Feb 25 '21 at 08:30
36

If you want to iterate over both the keys and the values in a key sorted order, this form is quite succinct

let d = [
    "A" : [1, 2],
    "Z" : [3, 4],
    "D" : [5, 6]
]

Swift 1,2:

for (k,v) in Array(d).sorted({$0.0 < $1.0}) {
    print("\(k):\(v)")
}

Swift 3+:

for (k,v) in Array(d).sorted(by: {$0.0 < $1.0}) {
    print("\(k):\(v)")
}
Joannes
  • 2,569
  • 3
  • 17
  • 39
rks
  • 451
  • 5
  • 3
29

I tried all of the above, in a nutshell all you need is

let sorted = dictionary.sorted { $0.key < $1.key }
let keysArraySorted = Array(sorted.map({ $0.key }))
let valuesArraySorted = Array(sorted.map({ $0.value }))
אורי orihpt
  • 2,358
  • 2
  • 16
  • 41
Elsammak
  • 1,102
  • 10
  • 26
  • That's amazing, first you sorted then get all keys and values. Because of this key and value is same in order not interchange. Thanks1 – Yogesh Patel Sep 05 '21 at 07:27
16

In swift 4 you can write it smarter:

let d = [ 1 : "hello", 2 : "bye", -1 : "foo" ]
d = [Int : String](uniqueKeysWithValues: d.sorted{ $0.key < $1.key })
Davide Gianessi
  • 283
  • 3
  • 4
  • 3
    Thanks for the effort but first of all, the "let" doesn't make the code build, so first it needs to be "var". Then after compile succeed this code doesn't work it doesn't sort the dictionary I get the same result before and after running this code. Maybe I am missing something but please elaborate more or change the code. ======= var d = [ 1 : "hello", 2 : "bye", -1 : "foo" ] print(d) ->>> prints [2: "bye", -1: "foo", 1: "hello"] d = [Int : String](uniqueKeysWithValues: d.sorted{ $0.key < $1.key }) print(d) ->>> prints [2: "bye", -1: "foo", 1: "hello"] – KarimIhab Jul 26 '18 at 14:45
  • It is not possible as when you convert it back to dictionary it will change to the unordered collection as dictionaries in swift are unordered collection https://developer.apple.com/documentation/swift/dictionary – Jaimin Jul 12 '19 at 10:49
12

Swift 4 & 5

For string keys sorting:

dictionary.keys.sorted(by: {$0.localizedStandardCompare($1) == .orderedAscending})

Example:

var dict : [String : Any] = ["10" : Any, "2" : Any, "20" : Any, "1" : Any]

dictionary.keys.sorted() 

["1" : Any, "10" : Any, "2" : Any, "20" : Any]

dictionary.keys.sorted(by: {$0.localizedStandardCompare($1) == .orderedAscending})

["1" : Any, "2" : Any, "10" : Any, "20" : Any]

shim
  • 9,289
  • 12
  • 69
  • 108
Xav Mac
  • 170
  • 1
  • 7
8

Swift 5

Input your dictionary that you want to sort alphabetically by keys.

// Sort inputted dictionary with keys alphabetically.
func sortWithKeys(_ dict: [String: Any]) -> [String: Any] {
    let sorted = dict.sorted(by: { $0.key < $1.key })
    var newDict: [String: Any] = [:]
    for sortedDict in sorted {
        newDict[sortedDict.key] = sortedDict.value
    }
    return newDict
}

dict.sorted(by: { $0.key < $1.key }) by it self returns a tuple (value, value) instead of a dictionary [value: value]. Thus, the for loop parses the tuple to return as a dictionary. That way, you put in a dictionary & get a dictionary back.

Krekin
  • 1,516
  • 1
  • 13
  • 24
  • 1
    Dictionary could not be sorted, because it contain hashable mappings – mazy Nov 25 '20 at 15:26
  • for me not. try: var dict = ["Alise": [1,3,2], "Jane": [2,5], "Dany": [1]] let sorted = sortWithKeys(dict) it returns ["Dany": [1], "Alise": [1, 3, 2], "Jane": [2, 5]], because Dictionary has nothing with sorting But sortedBy returns "[(key: "Alise", value: [1, 3, 2]), (key: "Dany", value: [1]), (key: "Jane", value: [2, 5])]\n" – mazy Nov 26 '20 at 16:31
  • 2
    When you create a new dictionary what is the guarantee that it will be sorted? – hariszaman Feb 17 '22 at 14:45
  • When creating a new dictionary you are simply setting keys and values so the order is not going to be respected. – Pau Senabre Sep 09 '22 at 16:00
7

For Swift 4 the following has worked for me:

let dicNumArray = ["q":[1,2,3,4,5],"a":[2,3,4,5,5],"s":[123,123,132,43,4],"t":[00,88,66,542,321]]

let sortedDic = dicNumArray.sorted { (aDic, bDic) -> Bool in
    return aDic.key < bDic.key
}
Bryan P
  • 4,142
  • 5
  • 41
  • 60
7

This is an elegant alternative to sorting the dictionary itself:

As of Swift 4 & 5

let sortedKeys = myDict.keys.sorted()

for key in sortedKeys {
   // Ordered iteration over the dictionary
   let val = myDict[key]
}
ThunderStruct
  • 1,504
  • 6
  • 23
  • 32
3

"sorted" in iOS 9 & xcode 7.3, swift 2.2 is impossible, change "sorted" to "sort", like this:

let dictionary = ["main course": 10.99, "dessert": 2.99, "salad": 5.99]
let sortedKeysAndValues = Array(dictionary).sort({ $0.0 < $1.0 })
print(sortedKeysAndValues)

//sortedKeysAndValues = ["desert": 2.99, "main course": 10.99, "salad": 5.99]
AmyNguyen
  • 437
  • 6
  • 10
2

For Swift 3, the following sort returnes sorted dictionary by keys:

let unsortedDictionary = ["4": "four", "2": "two", "1": "one", "3": "three"]

let sortedDictionary = unsortedDictionary.sorted(by: { $0.0.key < $0.1.key })

print(sortedDictionary)
// ["1": "one", "2": "two", "3": "three", "4": "four"]
Arijan
  • 297
  • 3
  • 6
  • 16
    This wont return a dictionary, this will return an array of Tuples – anoop4real Nov 02 '17 at 05:51
  • 2
    Don't you even read the question before putting your answer. You are wasting time of many people here. This question is specifically about sorting a dictionary and getting a sorted dictionary not array. I don't know why everyone is putting in wrong answers. – Shivam Pokhriyal Sep 14 '18 at 14:33
1

For Swift 3 the following has worked for me and the Swift 2 syntax has not worked:

// menu is a dictionary in this example

var menu = ["main course": 10.99, "dessert": 2.99, "salad": 5.99]

let sortedDict = menu.sorted(by: <)

// without "by:" it does not work in Swift 3
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Joeri
  • 29
  • 2
  • This answer is pretty incomplete. What is `sortedDict`? What is `menu`? This code does not appear to be valid, either. – random_user_name Aug 12 '16 at 16:22
  • Something more serious now: *a dictionary has no order*. What you get with your code is an array of tuples, not a sorted dictionary - as already said in some answers and comments. – Eric Aya Aug 15 '16 at 14:21
  • the topic is : sort dictionary by keys, I am answering to this topic. And it is a specific remark concerning only a syntax change in Swift 3, it doesn't deny anything from what has been written before. – Joeri Aug 15 '16 at 15:54
  • "This answer is pretty incomplete. What is sortedDict? What is menu? This code does not appear to be valid, either. – cale_b" The answer was edited, the only thing missing was a declaration for a dictionaty - menu. I thought it was clear, this is only about a syntax change in Swift 3 as indicated. The code does work in Swift 3. – Joeri Aug 16 '16 at 05:02
  • any suggestion for swift 4 plz? – famfamfam Sep 19 '18 at 10:13
1

Swift 3 is sorted(by:<)

let dictionary = [
    "A" : [1, 2],
    "Z" : [3, 4],
    "D" : [5, 6]
]

let sortedKeys = Array(dictionary.keys).sorted(by:<) // ["A", "D", "Z"]
Shadros
  • 728
  • 2
  • 10
  • 19
0

Swift Sort Dictionary by keys

Since Dictionary[About] is based on hash function it is not possible to use a sort function as we are used to(like Array). As an alternative you are able to implement a kind of Java TreeMap/TreeSet

Easiest way is to use .sorted(by:) function. It returns an sorted Array of key/value tupples which is easy to handle

Example:

struct Person {
    let name: String
    let age: Int
}

struct Section {
    let header: String
    let rows: [Int]
}

let persons = [
    Person(name: "A", age: 1),
    Person(name: "B", age: 1),
    Person(name: "C", age: 1),
    Person(name: "A", age: 2),
    Person(name: "B", age: 2),
    Person(name: "C", age: 2),
    Person(name: "A", age: 3),
    Person(name: "B", age: 3),
    Person(name: "C", age: 3),
]

//grouped
let personsGroupedByName: [String : [Person]] = Dictionary(grouping: persons, by: { $0.name })
/**
 personsGroupedByName
 [0] = {
   key = "B"
   value = 3 values {
     [0] = (name = "B", age = 1)
     [1] = (name = "B", age = 2)
     [2] = (name = "B", age = 3)
   }
 }
 [1] = {
   key = "A"
   value = 3 values {
     [0] = (name = "A", age = 1)
     [1] = (name = "A", age = 2)
     [2] = (name = "A", age = 3)
   }
 }
 [2] = {
   key = "C"
   value = 3 values {
     [0] = (name = "C", age = 1)
     [1] = (name = "C", age = 2)
     [2] = (name = "C", age = 3)
   }
 }
 */

//sort by key
let sortedPersonsGroupedByName: [Dictionary<String, [Person]>.Element] = personsGroupedByName.sorted(by: { $0.0 < $1.0 })
/**
 sortedPersonsGroupedByName
 [0] = {
     key = "A"
     value = 3 values {
       [0] = (name = "A", age = 1)
       [1] = (name = "A", age = 2)
       [2] = (name = "A", age = 3)
     }
   }
   [1] = {
     key = "B"
     value = 3 values {
       [0] = (name = "B", age = 1)
       [1] = (name = "B", age = 2)
       [2] = (name = "B", age = 3)
     }
   }
   [2] = {
     key = "C"
     value = 3 values {
       [0] = (name = "C", age = 1)
       [1] = (name = "C", age = 2)
       [2] = (name = "C", age = 3)
     }
   }
 */

//handle
let sections: [Section] = sortedPersonsGroupedByName.compactMap { (key: String, value: [Person]) -> Section in
    let rows = value.map { person -> Int in
        return person.age
    }
    return Section(header: key, rows: rows)
}
/**
 sections
 [0] = {
     header = "A"
     rows = 3 values {
       [0] = 1
       [1] = 2
       [2] = 3
     }
   }
   [1] = {
     header = "B"
     rows = 3 values {
       [0] = 1
       [1] = 2
       [2] = 3
     }
   }
   [2] = {
     header = "C"
     rows = 3 values {
       [0] = 1
       [1] = 2
       [2] = 3
     }
   }
 */
yoAlex5
  • 29,217
  • 8
  • 193
  • 205
0

my two cents, as all answers seem to miss we have a Dict and we do want a Dict:

var menu = ["main course": 10.99, "dessert": 2.99, "salad": 5.99]

let sortedMenu = menu.sorted(by: <) // is an ARRAY
print(type(of: sortedMenu))


let sortedDict = Dictionary( uniqueKeysWithValues: menu.sorted(by: <) )
print(type(of: sortedDict))

Above I sorted by value, by Key:

let sorted1 = menu.sorted { (kv1, kv2) in return kv1.key < kv2.key } and/or apply conversion to Dict using constructor.

ingconti
  • 10,876
  • 3
  • 61
  • 48