Sort Dictionary by keys
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 }
println(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.
Swift: A sorted dictionary
As has already been answered, the point of a dictionary is that it is not sorted. There are three types of collections in Swift (and Objective-C)
An array is an ordered list of items. Use this when the order of the items is important.
A dictionary is an unordered collection of keys and values. Use this when you want to efficiently retrieve a value based on a key.
A set is a bag of unordered, unique items. Use this when you want to have a collection of unique items in no particular order.
For your case it seems that the ordering is what is important to you, but you want to store some kind of pair of values. Perhaps what you should be looking at is using an array of tuples:
something like this, maybe
let dataPoints = [("A", 1), ("B", 2), ("C", 3)]
for (letter, number) in dataPoints {
print("\(letter), \(number)")
}
which outputs
A, 1
B, 2
C, 3
Alternatively
If you don't know about the order of the items before their creation, but there is a natural ordering based on the keys, you could do something like this:
let dict = [
"A" : 1,
"B" : 2,
"C" : 3
]
for key in dict.keys.sort() {
guard let value = dict[key] else { break }
print("\(key), \(value)")
}
In this case you get an array of keys with their default sort order (you can use a different sort function if you have other requirements) and output the key values based on that sorted order.
Sort a Dictionary in Swift
The output of sorted
function above is an Array. So you cannot get keys & values like a Dictionary. But you can use map
function to retrieve those sorted keys & values
Return an Array containing the sorted elements of
source
{according}.
The sorting algorithm is not stable (can change the relative order of
elements for which isOrderedBefore does not establish an order).
let codeValueDict = ["us": "$", "it": "€", "fr": "€"]
let sortedArray = sorted(codeValueDict, {$0.0 < $1.0})
print(sortedArray)
let keys = sortedArray.map {return $0.0 }
print(keys)
let values = sortedArray.map {return $0.1 }
print(values)
Sort dictionary by keys in Swift
Dictionary
already has a sorted
method that takes a closure that defines the sorting function. You can sort by keys in the closure, then simply map over the resulting tuples to get the values only.
let sortedDictKeys = dict.sorted(by: { $0.key < $1.key }).map(\.value)
Sort Dictionary by values in Swift
Try:
let dict = ["a":1, "c":3, "b":2]
extension Dictionary {
func sortedKeys(isOrderedBefore:(Key,Key) -> Bool) -> [Key] {
return Array(self.keys).sort(isOrderedBefore)
}
// Slower because of a lot of lookups, but probably takes less memory (this is equivalent to Pascals answer in an generic extension)
func sortedKeysByValue(isOrderedBefore:(Value, Value) -> Bool) -> [Key] {
return sortedKeys {
isOrderedBefore(self[$0]!, self[$1]!)
}
}
// Faster because of no lookups, may take more memory because of duplicating contents
func keysSortedByValue(isOrderedBefore:(Value, Value) -> Bool) -> [Key] {
return Array(self)
.sort() {
let (_, lv) = $0
let (_, rv) = $1
return isOrderedBefore(lv, rv)
}
.map {
let (k, _) = $0
return k
}
}
}
dict.keysSortedByValue(<)
dict.keysSortedByValue(>)
Updated:
Updated to the new array syntax and sort semantics from beta 3. Note that I'm using sort
and not sorted
to minimize array copying. The code could be made more compact, by looking at the earlier version and replacing sort
with sorted
and fixing the KeyType[]
to be [KeyType]
Updated to Swift 2.2:
Changed types from KeyType
to Key
and ValueType
to Value
. Used new sort
builtin to Array
instead of sort(Array)
Note performance of all of these could be slightly improved by using sortInPlace
instead of sort
Sort Dictionary by Key Value
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))
Swift: How to sort a dictionary by value, but the value is a tuple?
Dictionaries are not ordered and can't be sorted directly but you can sort the content which will give you an array of key value tuples. Then this array can be mapped to an array of keys which can be used to access the dictionary in a sorted fashion.
This will sort by the second value in the tuple and return an array of keys
let sorttedKeys = dict.sorted(by: { $0.value.1 < $1.value.1}).map {$0.key}
sorttedKeys.forEach {
print("\($0): \(dict[$0]!)")
}
b: (9, 1)
a: (3, 2)
c: (4, 3)
How to sort Dictionary by keys where values are array of objects in Swift 4?
struct Name: CustomStringConvertible {
let id: Int
let name: String
let native: String
let meaning: String
let origin: String
let isFavorite: Bool
let gender: String
var description: String {
return "Id: " + String(id) + " - Name: " + name
}
}
let name1 = Name(id: 1, name: "Tim Cook", native: "native", meaning: "meaning", origin: "origin", isFavorite: true, gender: "Male")
let name2 = Name(id: 2, name: "Steve Jobs", native: "native", meaning: "meaning", origin: "origin", isFavorite: true, gender: "Male")
let name3 = Name(id: 3, name: "Tiger Woods", native: "native", meaning: "meaning", origin: "origin", isFavorite: true, gender: "Male")
let name4 = Name(id: 4, name: "Socrates", native: "native", meaning: "meaning", origin: "origin", isFavorite: true, gender: "Male")
let names = [name1, name2, name3, name4]
let dictionary = names.sorted(by: {$0.name < $1.name }).reduce(into: [String: [Name]]()) { result, element in
// make sure there is at least one letter in your string else return
guard let first = element.name.first else { return }
// create a string with that initial
let initial = String(first)
// initialize an array with one element or add another element to the existing value
result[initial, default: []].append(element)
}
let sorted = dictionary.sorted {$0.key < $1.key}
print(sorted) // "[(key: "S", value: [Id: 4 - Name: Socrates, Id: 2 - Name: Steve Jobs]), (key: "T", value: [Id: 3 - Name: Tiger Woods, Id: 1 - Name: Tim Cook])]\n"
Related Topics
How to Bring Nswindow to Front and to the Current Space
How to Click a Button Programmatically
How to Trigger an Action When a Swiftui Toggle() Is Toggled
How to Convert Anyclass to a Specific Class and Init It Dynamically in Swift
Swift Test Give Error "Undefined Symbols for Architecture X86_64"
How to Create Uicollectionviewcell Programmatically
How to Change Navigationbar Font in Swift
Libsqlite3.Dylib and Libz.Dylib Missing in Xcode 7. How to Use Parse
How to Get the Current Queue Name in Swift 3
Swiftui - Add Border to One Edge of an Image
iOS 11 Large Title Navigation Bar Snaps Instead of Smooth Transition
Using Scenekit in Swift Playground
Adding Swift 3 Packages to Xcode 8 Using the Swift Package Manager
Expand and Contract Tableview Cell When Tapped, in Swift