Swift - Stored values order is completely changed in Dictionary
This is because of the definition of Dictionaries:
Dictionary
A dictionary stores associations between keys of the same type and values of the same type in an collection with no defined ordering.
There is no order, they might come out differently than they were put in.
This is comparable to NSSet.
Edit:
NSDictionary
Dictionaries Collect Key-Value Pairs. Rather than simply maintaining an ordered or unordered collection of objects, an NSDictionary stores objects against given keys, which can then be used for retrieval.
There is also no order, however there is sorting on print for debugging purposes.
Dictionary [String: String] keys order changed when converted to array swift
Use plain dictionary as tableview datasource is bad idea.
However Dictionary
can not be sorted. So it doesn't matter in what order you add your keys-values to the dictionary.
If you need sorted then use array of dictionary instead.
You should use models instead of plain dictionary that is easy to maintain :]
like
struct User {
var firstName:String?
var lastName:String?
var address:String?
var city:String?
}
Does a Swift Dictionary preserve same order if content is not changed regardless the number of runs?
As long as you don't modify a dictionary, the order of it's key/value pairs does not change. Everything else is unspecified. From the documentation (emphasis added):
The order of key-value pairs in a dictionary is stable between mutations but is otherwise unpredictable.
Note: This applies only to printing/enumerating the dictionary within a single program run. As @matt said, the order is randomized on each program run. And this is because the Hasher
is randomized:
Do not save or otherwise reuse hash values across executions of your program. Hasher is usually randomly seeded, which means it will return different values on every new execution of your program. The hash algorithm implemented by Hasher may itself change between any two versions of the standard library.
Hash randomization was enforced in Swift 4.2, with the implementation of SE 0206 Hashable Enhancements:
To implement nondeterminism, Hasher uses an internal seed value initialized by the runtime during process startup. The seed is usually produced by a random number generator, but this may be disabled by defining the SWIFT_DETERMINISTIC_HASHING environment variable with a value of 1 prior to starting a Swift process.
Preserve order of dictionary items as declared in Swift?
In your case an array of custom objects might be more appropriate.
Here is a simple example that should help to get you started:
struct Unit : Printable {
let name: String
let factor: Double
// println() should print just the unit name:
var description: String { return name }
}
let units = [
Unit(name: "kg", factor: 1000.0),
Unit(name: "g", factor: 1.0),
Unit(name: "mg", factor: 0.001),
Unit(name: "lb", factor: 453.592292),
Unit(name: "oz", factor: 28.349523)
]
println(units) // [kg, g, mg, lb, oz]
(I am not sure if the non-metric unit factors are correct :)
How to maintain the order of the data in Dictionary in Swift?
Short answer:
You can not maintain order in the Dictionary
.
Long answer:
Apple says:
Dictionaries are unordered collections of key-value associations.
Please refer this
To maintain the order you need to use the Array
or create sorted
Array
(Ascending, Descending or by using specific key) from the Dictionary
and use it.
Thank you.
Strange dictionary in swift
Becuase dictionaries have key pair values (a key being "1" and value being "!") it doesnt sort them in order like an array it will be different each time, (Where an array stores a value at a position that it was added) you can grab the value of a dictionary by knowing the key so it doesnt matter
Order changed for the parsed response when casting the response into a dictionary
Dictionary
's don't maintain key order.
Let's just start with some basic data...
struct ShowData: CustomStringConvertible {
var id: String
var time: String
var description: String {
return "id = \(id); time = \(time)"
}
}
var rawData: [String: [ShowData]] = [:]
rawData["2018-04-20"] = [
ShowData(id: "WRK81ahlWcZZ", time: "17:00:00"),
ShowData(id: "cDqZjYKHP2xt", time: "20:00:00")]
rawData["2018-04-21"] = [
ShowData(id: "DcVQhohv9C3W", time: "17:00:00"),
ShowData(id: "bZOUk3AT6TMM", time: "20:00:00")]
rawData["2018-04-22"] = [
ShowData(id: "5YJAydTua6b2", time: "17:00:00"),
ShowData(id: "qKGXgWvV0r38", time: "20:00:00")]
rawData["2018-04-23"] = [
ShowData(id: "AGciEXINppMe", time: "17:00:00"),
ShowData(id: "YbKFBJV67hFW", time: "20:00:00")]
rawData["2018-04-24"] = [
ShowData(id: "5vj9t1i5B4J3", time: "17:00:00"),
ShowData(id: "um7UeNPJuAcv", time: "20:00:00")]
rawData["2018-04-25"] = [
ShowData(id: "AbS69J4SM4gG", time: "17:00:00"),
ShowData(id: "AbS69J4SM4gG", time: "20:00:00")]
for key in rawData.keys {
print(key)
}
For me, this prints out...
2018-04-25
2018-04-24
2018-04-23
2018-04-21
2018-04-20
2018-04-22
Now, you could look to finding a OrderedDictionary
or you could Map
the keys to an array and sort the array, which would give you vector back into the Dictionary
Or, you could sort the Entry
data of the Dictionary
...
let sorted = rawData.sorted { (lhs, rhs) -> Bool in
return lhs.key < rhs.key
}
for entry in sorted {
print(entry.key)
}
Which outputs...
2018-04-20
2018-04-21
2018-04-22
2018-04-23
2018-04-24
2018-04-25
Now, what's important to remember here is, this is nothing more then a String
comparison, but you're dealing with dates. Personally, I hate dealing with String
date/time values and as soon as I can, I convert to something which is actually practical for there purpose...
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-mm-dd"
let actuallySortedByDate = rawData.sorted { (lhs, rhs) -> Bool in
return formatter.date(from: lhs.key)! < formatter.date(from: rhs.key)!
}
for entry in sorted {
print(entry.key)
}
Which outputs...
2018-04-20
2018-04-21
2018-04-22
2018-04-23
2018-04-24
2018-04-25
While this might not look any different from the first sorting, the comparisons performed are more actual to the data type (date objects).
Important
This is a demonstration of an idea. It's very important to understand that it's possible for the key to be invalid and the Date
conversion to fail. Personally, I'd prefer to have the rawData
keyed by Date
, rather the String
as it allows for an earlier detection of the issue. I've used a "forced unwrap" in the example purely for demonstration - you should validate the keys before hand and ensure that data is correct
Caveat: Mapping the keys in a Dictionary
is actually a lot harder then it would seem to need to be. You can have a look at What's the cleanest way of applying map() to a dictionary in Swift? for more details. Needs less to say, use Swift 4!
Okay, so what this attempts to do, is convert the original [String: ShowData]
Dictionary
to a [Date: ShowData]
Dictionary
in a way which would allow you to deal with the possibility of invalid String
keys.
enum ParserError: Error {
case invalidDateFormat
}
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-mm-dd"
do {
let mapped = try Dictionary(uniqueKeysWithValues: rawData.map({ (entry) throws -> (Date, [ShowData]) in
guard let date = formatter.date(from: entry.key) else {
throw ParserError.invalidDateFormat
}
return (Calendar(identifier: .gregorian).startOfDay(for: date), entry.value)
}))
let actuallySortedByDate = mapped.sorted { (lhs, rhs) -> Bool in
return lhs.key < rhs.key
}
for entry in actuallySortedByDate {
print(entry.key)
}
} catch let error {
print(error)
}
And this eventually ends up printing:
2018-01-19 13:00:00 +0000
2018-01-20 13:00:00 +0000
2018-01-21 13:00:00 +0000
2018-01-22 13:00:00 +0000
2018-01-23 13:00:00 +0000
2018-01-24 13:00:00 +0000
ps: The idea is to try and take the time component out of the equation
Related Topics
Uibutton Action in Table View Cell
Making Text Bold Using Attributed String in Swift
Nsurlconnection and Basic Http Authentication in Ios
How to Set the Width of a Cell in a Uitableview in Grouped Style
How to Perform Wireless Debugging in Xcode 9 With iOS 11, Apple Tv 4K, etc
iOS 7 Tableview Like in Settings App on iPad
How to Use Uiview Autoresizingmask Property Programmatically
Best Way to Add License Section to iOS Settings Bundle
Correct Singleton Pattern Objective C (Ios)
Understanding Performseguewithidentifier
How to Parse Json Response from Alamofire API in Swift
Stringbyappendingpathcomponent Is Unavailable
How to Run App in Simulator: Xcode Beta 6 iOS 8
How to Add Image and Text in Uitextview in Ios