11
let dict: [String:Int] = ["apple":5, "pear":9, "grape":1]

How do you sort the dictionary based on the Int value so that the output is:

sortedDict = ["pear":9, "apple":5, "grape":1]

Current Attempt (doesn't sort correctly):

let sortedDict = sorted(dict) { $0.1 > $1.1 } 
Onichan
  • 4,476
  • 6
  • 31
  • 60
  • 1
    Dictionary don't have sort order by design. They are key value container. – vikingosegundo Jul 20 '15 at 23:08
  • So I need to convert to an array, sort, then recreate the dictionary? – Onichan Jul 20 '15 at 23:18
  • 1
    Take a look at : http://stackoverflow.com/questions/24090016/sort-dictionary-by-values-in-swift – Lamour Jul 20 '15 at 23:20
  • I can't think of a use case where you'd need the dictionary to be sorted. What you usually want to do is obtain the keys as a list, order the list, then iterate over that ordered list to access the values. – Palpatim Jul 20 '15 at 23:20
  • @Emma, how would the recreated dictionary be able to have a sort order? – vikingosegundo Jul 20 '15 at 23:22
  • @palpatim i'm using the dictionary to store a string with an associated vote count. I would like to sort the values by highest > lowest votes (`Int` value in the dictionary). – Onichan Jul 20 '15 at 23:29
  • Emma In other words, you wish the values of the dictionary to be sorted, not the dictionary itself. It's a subtle wording change, but a profoundly different way of thinking about the problem. @lamar's reference above will give you some pointers in sorting a dictionary by value. It will be up to you to then construct a list (e.g., an Array) of the key-value pairs in the order you want. – Palpatim Jul 20 '15 at 23:34

4 Answers4

34

You need to sort your dictionary values, not your keys. You can create an array of tuples from your dictionary sorting it by its values as follow:

Xcode 9 • Swift 4 or Xcode 8 • Swift 3

let fruitsDict = ["apple": 5, "pear": 9, "grape": 1]
let fruitsTupleArray = fruitsDict.sorted{ $0.value > $1.value }

fruitsTupleArray // [(.0 "pear", .1 9), (.0 "apple", .1 5), (.0 "grape", .1 1)]

for (fruit,votes) in fruitsTupleArray {
    print(fruit,votes)
}

fruitsTupleArray.first?.key   // "pear"
fruitsTupleArray.first?.value   // 9

To sort your dictionary using your keys

let fruitsTupleArray = fruitsDict.sorted{ $0.key > $1.key }
fruitsTupleArray  // [(key "pear", value 9), (key "grape", value 1), (key "apple", value 5)]

To sort your dictionary using its keys and localized comparison:

let fruitsTupleArray = fruitsDict.sorted { $0.key.localizedCompare($1.key) == .orderedAscending  }

edit/update:

We can also extend Sequence protocol and implement a custom sort that takes a predicate and sort using a keypath property as long as it conforms to Comparable:

extension Sequence {
    func sorted<T: Comparable>(_ predicate: (Element) -> T, by areInIncreasingOrder: ((T,T)-> Bool) = (<)) -> [Element] {
        sorted(by: { areInIncreasingOrder(predicate($0), predicate($1)) })
    }
}

Usage:

let sortedFruitsAscending = fruitsDict.sorted(\.value)
print(sortedFruitsAscending)

let sortedFruitsDescending = fruitsDict.sorted(\.value, by: >)
print(sortedFruitsDescending)

This will print

[(key: "grape", value: 1), (key: "apple", value: 5), (key: "pear", value: 9)]

[(key: "pear", value: 9), (key: "apple", value: 5), (key: "grape", value: 1)]


edit/update:

For Xcode 13 or later you can use a new generic structure called KeyPathComparator:

let fruitsTupleArray = fruitsDict.sorted(using: KeyPathComparator(\.value, order: .reverse))
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • 1
    This was the answer I was looking for. Extremely simple, readable and independent. Works with Swift 4.2 and Xcode 10.1. Thank you very much! – emreerokyar Dec 15 '18 at 15:19
3

Dictionaries can't be sorted. Generally, when I need things sorted from a dictionary, I will make a separate array of my dictionary keys.

In your case, make an array of the keys, sort them by comparing their values in the dictionary.

boboguitar
  • 66
  • 9
0

It can be achieved by using the below implementation

let sortedDictionary = unsortedDictionary.sorted{$0.key > $1.key}

0

use KeyValuePairs instead of Dictionary

"The order of key-value pairs in a dictionary is stable between mutations but is otherwise unpredictable. If you need an ordered collection of key-value pairs and don’t need the fast key lookup that Dictionary provides, see the KeyValuePairs type for an alternative." - Swift Dictionary

atom2ueki
  • 837
  • 4
  • 15
  • 32