Search in NSMutableArray - swift

I am wanted to make a search on NSMUtableArray with key values to catch the hole object not just an array of values so for example my NSMUtableArray return me
{id : 1, name : x1}
{id : 2, name : x2}
{id : 3, name : x3}
{id : 4, name : y1}
{id : 5, name : y2}
if I am searching of x my code return me
{x1,x2,x3}
or I want it to return
{id : 1, name : x1}
{id : 2, name : x2}
{id : 3, name : x3}
my code is :
let arrayy = lstResults.value(forKey: "name")
let searchTest = NSPredicate(format: "SELF BEGINSWITH [c] %#", searchBar.text!)
let array = (arrayy as! NSArray).filtered(using: searchTest)
filteredTableDataName = array as NSArray
please help I tried a lot of stuff but nothing worked form me.

Instead of extracting and filtering the "name" values you can filter the array directly, using the corresponding key path instead of “SELF” in the predicate:
let array = NSArray(array: [
["id": 1, "name": "x1"], ["id": 2, "name": "x2"], ["id": 3, "name": "y3"]])
let predicate = NSPredicate(format: "name BEGINSWITH [c] %#", "x")
let filtered = array.filtered(using: predicate)
print(filtered)
Result:
[{
id = 1;
name = x1;
}, {
id = 2;
name = x2;
}]
Another option is to cast the NS(Mutable)Array to a Swift array of dictionaries, and use the filter() function:
if let a = array as? [[String: Any]] {
let filtered = a.filter {
($0["name"] as? String)?
.range(of: "x", options: [.caseInsensitive, .anchored]) != nil
}
print(filtered)
// [["id": 1, "name": x1], ["name": x2, "id": 2]]
}

NSMutableArray (or NSArray for that matter) are leftovers from the 'Objective-c' era.
For this purpose there is not real need using it or not using Swift's standard generic Array<Element> => https://developer.apple.com/documentation/swift/array
Might I consider creating a struct instead of using a dictionary:
import Foundation
struct Obj {
let id: Int
let name: String
}
let array = [
Obj(id: 1, name: "x1"),
Obj(id: 2, name: "x2"),
Obj(id: 3, name: "X3"),
Obj(id: 4, name: "y1"),
Obj(id: 5, name: "y2")
]
let filteredArray = array.filter { $0.name.localizedLowercase.hasPrefix("x") }
// filteredArray = [
// Obj(id: 1, name: "x1"),
// Obj(id: 2, name: "x2"),
// Obj(id: 3, name: "X3")
// ]
Else you would have something like this:
import Foundation
let array: [[String: Any]] = [
[ "id": 1, "name": "x1" ],
[ "id": 2, "name": "x2" ],
[ "id": 3, "name": "X3" ],
[ "id": 4, "name": "y1" ],
[ "id": 5, "name": "y2" ]
]
let filteredArray = array.filter { ($0["name"] as? String)?.localizedLowercase.hasPrefix("x") == true }

Related

How can I sort dictionary [duplicate]

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.
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.
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 })
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 })
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}) {
println("\(k):\(v)")
}
Swift 3+:
for (k,v) in Array(d).sorted(by: {$0.0 < $1.0}) {
println("\(k):\(v)")
}
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 }))
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 })
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]
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.
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
}
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]
}
"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]
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"]
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
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"]
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
}
}
*/
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.

Can I request a two-dimensional associative array in swift Moya?

The following two forms of data were successfully requested.
{
"ride_fare": 1000,
"km": 7
]
}
{
"ride_fare": 1000,
"km": 7,
"options": [ 0, 1, 2]
}
However, I don't know how to request a two-dimensional associative array like the one below.
How can I request it?
{
"ride_fare": 1000,
"km": 7,
"option_fares": [
{
"price": 200,
"name": "立ち寄り",
"id": 1
}
]
}
The code that I wrote:
var options = [Any]()
for option in optionFares {
let params = [
"id" : option.id ?? 0,
"name" : option.name ?? "",
"price" : option.price ?? 0
] as [String : Any]
options.append(params)
}
let faresData = [
"id" : driverOrder.id ?? 0,
"km" : driverOrder.distance ?? 0,
"option_fares" : options,
"ride_fare" : driverOrder.ride_fare ?? 0
] as [String : Any]
First, create a struct that matches the json format you want to request.
struct Params: Codable {
let rideFare, km: Int
let optionFares: [OptionFare]
enum CodingKeys: String, CodingKey {
case rideFare = "ride_fare"
case km
case optionFares = "option_fares"
}
}
struct OptionFare: Codable {
let price: Int
let name: String
let id: Int
}
And you must create a request parameter in Moya's task.
import Moya
extension APITarget: TargetType {
var task: Task {
case .yourCaseName(let price, let name, let id, let rideFare, let km):
let encoder: JSONEncoder = JSONEncoder()
let optionFareData: [OptionFare] = []
optionFareData.append(OptionFare(price, name, id))
let paramsData = Params(rideFare, km, optionFareData)
let jsonData: Data = try! encoder.encode(paramsData)
return .requestData(jsonData)
}
}
}

How to add multiple dictionary into array

I've got a dictionary added into array. I would like to add second dictionary into the array. How to do it?
var dict = [String: AnyObject]()
dict = ["description": self.odrRefTxt.text as AnyObject,
"weight": self.pWeight as AnyObject,
"quantity": self.qtyTxt.text as AnyObject,
"unitPrice": self.valueTxt.text as AnyObject,
"currency": self.pCurrency as AnyObject]
// saving to memory
UserDefaults.standard.set(dict, forKey: "addItem")
// getting from memory
let addItem = UserDefaults.standard.value(forKey: "addItem")
print(addItem as Any)
//add new item into list of items
self.itemArr.append(addItem as Any)
print(self.itemArr)
Below are the result from print:
//print addItem
Optional({
currency = "";
description = "Toyo Proxes";
quantity = 4;
unitPrice = 100;
weight = 0;
})
//print self.itemArr
[Optional({
currency = "";
description = "Toyo Proxes";
quantity = 4;
unitPrice = 100;
weight = 0;
})]
For example, I would like to add the 2nd dictionary into the array to print out the outcome like this:
//print self.itemArr
[Optional({
currency = "";
description = "Toyo Proxes";
quantity = 4;
unitPrice = 100;
weight = 0;
},
{
currency = "";
description = "Yokohama Advan";
quantity = 2;
unitPrice = 250;
weight = 0;
})]
You save something in UserDefaults as Any, so just cast it to the original type and here you go.
Modified with #rmaddy's suggestion.
var itemArr = [[String: Any]]()
var dict = [String: Any]()
dict = ["description": 1,
"weight": 2,
"quantity": 3,
"unitPrice": "abc",
"currency": "123"]
// saving to memory
UserDefaults.standard.set(dict, forKey: "addItem")
// getting from memory
if let addItem = UserDefaults.standard.dictionary(forKey: "addItem") {
itemArr.append(addItem)
}
let dict2:[String: Any] = ["description": 4,
"weight": 5,
"quantity": 6,
"unitPrice": "xyz",
"currency": "456"]
itemArr.append(dict2)
print(itemArr)
// prints out:
// [["description": 1, "quantity": 3, "weight": 2, "currency": 123, "unitPrice": abc], ["description": 4, "weight": 5, "quantity": 6, "currency": "456", "unitPrice": "xyz"]]

How to deep merge 2 Swift dictionaries

My question is simple, I want to know how to do a deep merge of 2 Swift dictionaries (not NSDictionary).
let dict1 = [
"a": 1,
"b": 2,
"c": [
"d": 3
],
"f": 2
]
let dict2 = [
"b": 4,
"c": [
"e": 5
],
"f": ["g": 6]
]
let dict3 = dict1.merge(dict2)
/* Expected:
dict3 = [
"a": 1,
"b": 4,
"c": [
"d": 3,
"e": 5
],
"f": ["g": 6]
]
*/
When dict1 and dict2 have the same key, I expect the value to be replaced, but if that value is another dictionary, I expect it to be merged recursively.
Here is the solution I'd like:
protocol Mergeable {
mutating func merge(obj: Self)
}
extension Dictionary: Mergeable {
// if they have the same key, the new value is taken
mutating func merge(dictionary: Dictionary) {
for (key, value) in dictionary {
let oldValue = self[key]
if oldValue is Mergeable && value is Mergeable {
var oldValue = oldValue as! Mergeable
let newValue = value as! Mergeable
oldValue.merge(newValue)
self[key] = oldValue
} else {
self[key] = value
}
}
}
}
but it gives me the error Protocol 'Mergeable' can only be used as a generic constraint because it has Self or associated type requirements
EDIT:
My question is different from Swift: how to combine two Dictionary instances? because that one is not a deep merge.
With that solution, it would produce:
dict3 = [
"a": 1,
"b": 4,
"c": [
"e": 5
]
]
In my view the question is incoherent. This is an answer, however:
func deepMerge(d1:[String:AnyObject], _ d2:[String:AnyObject]) -> [String:AnyObject] {
var result = [String:AnyObject]()
for (k1,v1) in d1 {
result[k1] = v1
}
for (k2,v2) in d2 {
if v2 is [String:AnyObject], let v1 = result[k2] where v1 is [String:AnyObject] {
result[k2] = deepMerge(v1 as! [String:AnyObject],v2 as! [String:AnyObject])
} else {
result[k2] = v2
}
}
return result
}
Here is your test case:
let dict1:[String:AnyObject] = [
"a": 1,
"b": 2,
"c": [
"d": 3
]
]
let dict2:[String:AnyObject] = [
"b": 4,
"c": [
"e": 5
]
]
let result = deepMerge(dict1, dict2)
NSLog("%#", result)
/*
{
a = 1;
b = 4;
c = {
d = 3;
e = 5;
};
}
*/
3rd-party edit: Alternate version using variable binding and newer Swift syntax.
func deepMerge(_ d1: [String: Any], _ d2: [String: Any]) -> [String: Any] {
var result = d1
for (k2, v2) in d2 {
if let v1 = result[k2] as? [String: Any], let v2 = v2 as? [String: Any] {
result[k2] = deepMerge(v1, v2)
} else {
result[k2] = v2
}
}
return result
}
How about manually doing it.
func += <KeyType, ValueType> (inout left: Dictionary<KeyType, ValueType>, right: Dictionary<KeyType, ValueType>) {
for (k, v) in right {
left.updateValue(v, forKey: k)
}
}
You can also try ExSwift Library
extension Dictionary {
mutating func deepMerge(_ dict: Dictionary) {
merge(dict) { (current, new) in
if var currentDict = current as? Dictionary, let newDict = new as? Dictionary {
currentDict.deepMerge(newDict)
return currentDict as! Value
}
return new
}
}
}
How to use/test:
var dict1: [String: Any] = [
"a": 1,
"b": 2,
"c": [
"d": 3
],
"f": 2
]
var dict2: [String: Any] = [
"b": 4,
"c": [
"e": 5
],
"f": ["g": 6]
]
dict1.deepMerge(dict2)
print(dict1)

Sort Dictionary by keys

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.
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.
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 })
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 })
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}) {
println("\(k):\(v)")
}
Swift 3+:
for (k,v) in Array(d).sorted(by: {$0.0 < $1.0}) {
println("\(k):\(v)")
}
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 }))
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 })
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]
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.
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
}
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]
}
"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]
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"]
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
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"]
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
}
}
*/
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.