Sort Dictionary [Key: [Key: Value]] by value - Swift - swift

I have a dictonary that looks like this:
var dict = [Int: [String: Any]]()
dict[1] = ["nausea": 23, "other": "hhh"]
dict[2] = ["nausea": 3, "other": "kkk"]
dict[3] = ["nausea": 33, "other" : "yyy"]
I want to sort the dictionary by the value of the dictionary value for key "nausea" from least to greatest.
To look like this:
sortedDict = [2: ["nausea": 3, "other": "kkk"], 1: ["nausea": 23, "other": "hhh"], 3: ["nausea": 33, "other" : "yyy"]]
I tried to play around with it using .sort():
let sortedDict = dict.sort( { ($0["nausea"] as! Int) > ($1["nausea"] as! Int) })
but, obviously It didn't work because "nausea" isn't the key for the dictonary
Can someone show me how they would do this?
Thanks in advance!

A Dictionary is unordered by design, as the documentation clearly states:
Every dictionary is an unordered collection of key-value pairs.
You are probably looking for an ordered type like Array.
var arrayDict = [
["nausea": 23, "other": "hhh"],
["nausea": 3, "other": "kkk"],
["nausea": 33, "other" : "yyy"]
]
let sorted = arrayDict.sorted { $0["nausea"] as! Int < $1["nausea"] as! Int }
print(sorted)
Update: Even better as #LeoDabus suggested in the comment you can use an array of custom objects:
struct MyObject {
var nausea: Int
var other: String
}
var array = [
MyObject(nausea: 23, other: "hhh"),
MyObject(nausea: 3, other: "kkk"),
MyObject(nausea: 33, other: "yyy")
]
let sorted = array.sorted { $0.nausea < $1.nausea }
print(sorted)

Related

Create dictionary with objects and array statically and get their value

I am trying to create a dictionary in a static way and obtain the data, but I am not correct. I mean because it is only an array of string and any, but in the image it has brackets and braces. Any help I will appreciate a lot, thanks for your time
let responseDevice : [String : Any] = [
"date_s" : "2021-02-18",
"id_c" : "4",
"id_d" : 1,
"data" : [
"Peso" : 34,
"Fc" : -1,
"Age" : 34,
"Name" : "July"
],
"flags" : 0,
"error" : 0
]
if let date_s = responseDevice["date_s"] as? String,
let dat = responseDevice["data"] as? [String : Any],
let peso = dat["Peso"] as? Int {
print(date_s)
print(peso)
}
print("log :\(responseDevice)")
result:
2021-02-18
34
log :["id_c": "4", "error": 0, "id_d": 1, "flags": 0, "date_s": "2021-02-18", "data": ["Peso": 34, "Fc": -1, "Age": 34, "Name": "July"]]
What you created is a Swift Dictionary. What you have on that image is JSON Object. It's not very clear what your goal is, so couple of basic pointers:
If you want to parse JSON into Dictionary, check this answer
If you simply want to include some JSON sample in your code (e.g. for testing), you can put it in triple quotes:
var myJSON = """
[paste your JSON here]
"""

How to create a sub-Dictionary from a Dictionary?

I am wondering what is the best way to initialize a 'child' Dictionary with specified key/value pairs from a 'parent' Dictionary. As an example,
parent dictionary looks like:
["name": "Joe", "age": 45, "occupation": scientist]
Now I want to quickly create a child dictionary that only uses the "name" and "age" kv pairs
child dictionary should look like:
["name": "Joe", "age": 45]
Is there a supported Swift dictionary function that can do this? Thanks
One way to do it is to filter the dictionary:
let dict: [String : Any] = ["name": "Joe", "age": 45, "occupation": "scientist"]
let newkeys = ["name", "age"]
let newdict = dict.filter { newkeys.contains($0.key) }
If your original dictionary is large, and the new keys are small by comparison, it might be quicker to construct a new dict like so:
let newdict = newkeys.reduce(into: [:]) { $0[$1] = dict[$1] }

How to sort array of NSMutableDictionary store in NSUserDefault?

I have an array of NSMutableDictionary saved with NSUserDefault , I want to sort the array based on "timestamp" key (the value is a String) in each NSMutableDictionary :
that the code I use to retrieve the array:
if let chatsArray = NSUserDefaults().arrayForKey("myChatsList") as? [NSMutableDictionary]{
print(chatsArray)
//sort the array
print(sortedArray)
}
thats how my array look like:
[{
eventBadge = 1;
eventId = "-KWE39B6Dh7rDzaF-xy4";
lastMessage = uyfgduihgvifudhviufhvdf;
timestamp = 20;
unreadMessage = 2;
}, {
eventBadge = 1;
eventId = "-KWWc99ex8f7ksq8TR2U";
lastMessage = uyfgduihgvifudhviufhvdf;
timestamp = 5;
unreadMessage = 1;
}, {
eventBadge = 1;
eventId = "-KWE5OYRZnZ5-p3LUotL";
lastMessage = uyfgduihgvifudhviufhvdf;
timestamp = 10;
unreadMessage = 2;
}]
I try to use NSSDescriptor :
var descriptor: NSSortDescriptor = NSSortDescriptor(key: "timestamp", ascending: true)
chatsArray.sortedArrayUsingDescriptors([descriptor])
and also to use a typed array (after using a new class)
mutableChatsArray.sortInPlace{ ($0.compare($1.timestamp) == NSComparisonResult.OrderedDescending)}
So far without success...
Thanks for your help
Swift 3 example
let chatsArray = [[
"eventBadge" : 1,
"eventId" : "-KWE39B6Dh7rDzaF-xy4",
"lastMessage" : "uyfgduihgvifudhviufhvdf",
"timestamp" : 20,
"unreadMessage" : 2,
], [
"eventBadge" : 1,
"eventId" : "-KWWc99ex8f7ksq8TR2U",
"lastMessage" : "uyfgduihgvifudhviufhvdf",
"timestamp" : 5,
"unreadMessage" : 1,
], [
"eventBadge" : 1,
"eventId" : "-KWE5OYRZnZ5-p3LUotL",
"lastMessage" : "uyfgduihgvifudhviufhvdf",
"timestamp" : 10,
"unreadMessage" : 2,
]] as [[String:Any]]
// to get the timestamp value and store it inside an array with order
let arrayTimeStamp = (chatsArray.flatMap{$0["timestamp"]} as! Array<Int>).sorted(by: >)
print(arrayTimeStamp) // [20, 10, 5]
//to order an array of dictionaries
let TimeStamp = chatsArray.sorted{$0["timestamp"] as! Int > $1["timestamp"] as! Int }
print(TimeStamp)
//[["eventId": "-KWE39B6Dh7rDzaF-xy4", "lastMessage":"uyfgduihgvifudhviufhvdf", "timestamp": 20, "unreadMessage": 2, "eventBadge": 1],
//["eventId": "-KWE5OYRZnZ5-p3LUotL", "lastMessage": "uyfgduihgvifudhviufhvdf", "timestamp": 10, "unreadMessage": 2, "eventBadge": 1],
//["eventId": "-KWWc99ex8f7ksq8TR2U", "lastMessage": "uyfgduihgvifudhviufhvdf", "timestamp": 5, "unreadMessage": 1, "eventBadge": 1]]
Working with NSUserDefaults can be very annoying. I usually follow this technique when getting and setting data from the defaults.
var mutableArray = defaults.objectForKey("Your Array") as? NSMutableArray
mutableArray.sortInPlace { (a, b) -> Bool in
a.start!.compare(b.start!) == NSComparisonResult.OrderedAscending
}
defaults.setValue(mutableArray forKey: "Your Array")
#Rob and #Fallah , thanks for your answers , Im gonna check them, for now I solve my issue by using the NNSSDescriptor and add it a selector:
let descriptor: NSSortDescriptor = NSSortDescriptor(key: "timestamp", ascending: true, selector: #selector(NSString.localizedStandardCompare(_:)))
let sortedChatsArray = (chatsArray as NSArray).sortedArrayUsingDescriptors([descriptor])

Dictionary wrong order - JSON

I am trying to create a dictionary that I can make into a JSON formatted object and send to the server.
Example:
var users = [
[
"First": "Albert",
"Last": "Einstein",
"Address":[
"Street": "112 Mercer Street",
"City": "Princeton"]
],
[
"First": "Marie",
"Last": "Curie",
"Address":[
"Street": "108 boulevard Kellermann",
"City": "Paris"]]
]
I use this function
func nsobjectToJSON(swiftObject: NSObject) -> NSString {
var jsonCreationError: NSError?
let jsonData: NSData = NSJSONSerialization.dataWithJSONObject(swiftObject, options: NSJSONWritingOptions.PrettyPrinted, error: &jsonCreationError)!
var strJSON = NSString()
if jsonCreationError != nil {
println("Errors: \(jsonCreationError)")
}
else {
// everything is fine and we have our json stored as an NSData object. We can convert into NSString
strJSON = NSString(data: jsonData, encoding: NSUTF8StringEncoding)!
println("\(strJSON)")
}
return strJSON
}
But my result is this:
[
{
"First" : "Albert",
"Address" : {
"Street" : "112 Mercer Street",
"City" : "Princeton"
},
"Last" : "Einstein"
},
{
"First" : "Marie",
"Address" : {
"Street" : "108 boulevard Kellermann",
"City" : "Paris"
},
"Last" : "Curie"
}
]
Problem: why is the last name last? I think it should be above address. Please let me know what I am doing wrong with the NSDictionary for this to come out wrong. Any help would be very much appreciated - thank you.
To post what has already been said in comments: Dictionaries are "unordered collections". They do not have any order at all to their key/value pairs. Period.
If you want an ordered collection, use something other than a dictionary. (an array of single-item dictionaries is one way to do it.) You can also write code that loads a dictionary's keys into a mutable array, sorts the array, then uses the sorted array of keys to fetch key/value pairs in the desired order.
You could also create your own collection type that uses strings as indexes and keeps the items in sorted order. Swift makes that straightforward, although it would be computationally expensive.
I did like this.
let stagesDict = NSDictionary()
if let strVal = sleepItemDict["stages"] as? NSDictionary {
stagesDict = strVal
let sortedKeys = (stagesDict.allKeys as! [String]).sorted(by: <)
var sortedValues : [Int] = []
for key in sortedKeys {
let value = stagesDict[key]!
print("\(key): \(value)")
sortedValues.append(value as! Int)
}
}

Searching in Array of Dictionaries

I'm trying to search values in array of dictionaries which I get from JSON. I have a tableViewController with UISearchResultsUpdating. I found an example with array of Strings:
func updateSearchResultsForSearchController(searchController: UISearchController)
{
filteredTableData.removeAll(keepCapacity: false)
let searchPredicate = NSPredicate(format: "SELF contains[c] %#", searchController.searchBar.text)
let array = tableData.filteredArrayUsingPredicate(searchPredicate)
filteredTableData = array as! [String]
self.tableView.reloadData()
}
And I really don't know how to made search in array like this:
(
{
id = 3;
name = TestNewYork;
},
{
id = 2;
name = TestLA;
},
{
id = 1;
name = TestWashington;
}
)
my tableData = [] and filteredTableData must be an array too
Please, help!
You can use a simple filter function to do this...
tableData : [[String : String]] = ... // your JSON array of String, String dictionaries...
filteredTableData = tableData.filter{
dictionary in
return dictionary["name"] == filterString
}
Something like that anyway, not written Swift for a while.
You can wrap it in a function too...
func filter(array : [[String : String]], byString filterString : String) -> [[String : String]] {
return array.filter{
dictionary in
return dictionary["name"] == filterString
}
}
Or something. Not checked the code yet. Will be back if it doesn't work.
Checked in Playground and this works...
UPDATE
Changed to this...
let data = [
[
"id" : 3,
"name" : "a"
],
[
"id" : 4,
"name" : "b"
],
[
"id" : 5,
"name" : "c"
]
]
let filteredData = data.filter{
return $0["name"] == "b"
}
And it works. Just can't work out how to wrap in a function.
If you want to match the beginning of words...
let data = [
[
"id" : 3,
"name" : "Hello"
],
[
"id" : 4,
"name" : "Goodbye"
],
[
"id" : 5,
"name" : "Everybody"
]
]
let filteredData = data.filter{
let string = $0["name"] as! String
return string.hasPrefix("Goo")
}
If you want a contains you just need to do a find in the string.
Again, I'm not lying here. I'm running it in a Playground to check...
For a contains search you can do this...
let filteredData = data.filter{
let string = $0["name"] as! String
return string.rangeOfString("db") != nil
}