Sort array of dictionaries by date key - ios

I have a [[Date:[Double]]] which I would like to sort by nearest to farthest date based on the element's key, which is a date.
What is the most efficient way to do this using Swift? I have done this before using NSSortDescriptor but this was when sorting using a key/value pair. I have not sorted by the actual key itself before.
Example data:
[[2020-12-18 06:00:00 +0000: [475.4]], [2020-11-06 06:00:00 +0000: [427.475, 449.22]], [2020-11-06 00:09:33 +0000: [435.26, 441.605]]]

As Matt suggests, make your model like this:
struct DateStruct {
let date: Date
let values: [Double]
}
var dateStructsArray: [DateStruct] = []
//Populate your array in whatever way makes sense
Then sorting it is as simple as using a single call to sorted()
Your code might look like this:
let sortedDateStructs = dateStructsArray.sorted { $0.date < $1.date }

As Duncan Suggests:
first:Parsing data what you want,
second:set data to dateStruct for a array,you can use the array to do something.

Related

Sort received dates from response in swift

I am working on code where I am receiving lots of data associated with dates
each object having one date parameter and there might many objects with the same date.
I need to show this all objects in UITableView. each object as one cell.
I succeed in that,
I need to get unique dates from the response array of objects.
Those unique dates will be stored in an array which will act as a number of sections of my table view with section header title will be the date from the unique date array.
somehow I am able to sort out that with what I want,
The only problem I am facing is I am not able to sort the unique date array
every time the sequence change.
I need the latest date as the first date and the oldest date as the end date.
How to achieve this in swift.
Following is a piece of code I have written
let sortedKeys = Array(dictValue.keys).sorted(by: {$0 > $1})
print(sortedKeys)
here dicValue.keys is my unique date array and I wanted to sort it.
Following is a sample response I am getting
["08/03/2021”, “10/02/2021”, "26/04/2021", "25/03/2021”, "09/12/2020”, , "27/04/2021”, "23/03/2021”, "11/01/2021”, "05/03/2021”, "09/03/2021”, "16/10/2020", "19/03/2021", "12/10/2020" ]
and after applying sort I am getting the following output
[“27/04/2021", "26/04/2021", "25/03/2021", "23/03/2021", "19/03/2021", "16/10/2020", "12/10/2020", "11/01/2021", "10/02/2021", "09/12/2020", "09/03/2021", "08/03/2021", "05/03/2021”]
where dates are not properly sorted out.
Can anyone please help me out with it.
Thanks in advance.
This string date format is inappropriate for sorting, because the most significant component is day. Only a date format like yyyy/MM/dd can be sorted properly by comparison operator >.
However this is Swift. The closure can contain anything as long as it returns a Bool. You could sort the array with a custom sort algorithm. It splits the strings into components and sorts first year then month then day
let sortedKeys = dictValue.keys.sorted { (date1, date2) -> Bool in
let comps1 = date1.components(separatedBy: "/")
let comps2 = date2.components(separatedBy: "/")
return (comps1[2], comps1[1], comps1[0]) > (comps2[2], comps2[1], comps2[0])
}
print(sortedKeys)
If you want to sort a date, just sort a Date. Date supports Hashable and can be used as a dictionary key, you could map your original dictionary and by using a DateFormatter to format your string keys into Dates then you can easily sort them.
let dictionary = ["08/03/2021": 2, "10/02/2021": 5, "26/04/2021" : 6]
let formatter = DateFormatter()
formatter.dateFormat = "dd/MM/yyyy" // You should probably adjust other properties of the formatter
let newDict = Dictionary(uniqueKeysWithValues:
dictionary.map { (key, value) -> (Date, Int) in
print("Key: \(key)")
return (formatter.date(from: key)!, value)
})
let sortedDates = newDict.keys.sorted { $0 > $1 }
let value = newDict[sortedDates[0]]

Firestore: How can I correctly order by string with accent characters?

My Firestore database include words with accent characters, such as the acute (é), tilde (ñ), umlaut (ü), and cedilla (ç).
I've created a custom index to order by this field, but the words with such characters are not correctly positioned.
Example of expected order:
["Água", "Amigo", "Barro", "Casa"]
What I'm getting from Firestore:
["Amigo", "Barro", "Casa", "Água"]
My query is as such:
let query = historyRef.whereField("createdByUserID", isEqualTo: state.loggedUser.uid).order(by: "itemName", descending: false)
Any pointers on how to fix it?
Thanks in advance.
You can order your array collection like this:
var array = ["Amigo", "Barro", "Casa", "Água"]
array = array.sorted(by: {
$0.lowercased().folding(options: .diacriticInsensitive, locale: .current)
<
$1.lowercased().folding(options: .diacriticInsensitive, locale: .current)
})
As far as I know, Firebase has no built-in option to sort ignoring diacritical marks. What you can do is add a foldedName property to your objects, and then have Firebase sort on that. To get this folded name, use
itemName.folding(options: [.diacriticInsensitive, .caseInsensitive], locale: Locale.current)
I also had an issue sorting strings with diacritic marks (i.e., "Pâté"). I was using NSSortDescriptor to sort items fetched from Core Data, but it turns out that NSSortDescriptor can't sort this kind of strings well.
So I fetched the array of items without a NSSortDescriptor, then I manually sorted them with:
func sortArray() {
array.sort(by: { item1, item2 in
return item1.itemName?.localizedStandardCompare((item2.itemName)!) == .orderedAscending } )
}

Swift 3: how to sort Dictionary's key and value of struct

This is my Struct,by Swift 3. I know the Dictionary is not stored sequence like an Array and that is my problem. I want to get my Dictionary sequence as I set in ViewArray. I can get the ctC Dictionary, but how can i sort the keys or values as i set in ViewArrayplease and appreciate the help.
struct CTArray {
var ctname: String
var ctkey: String
var ctC: [String:String]
}
var ViewArray:[CTArray] = []
ViewArray += [CTArray(ctname: "kerish", ctkey: "KH", ctC: ["mon":"Apple", "kis":"aone", "Bat":"Best", "orlno":"bOne"])]
ViewArray += [CTArray(ctname: "tainers", ctkey: "TNN", ctC: ["letGor":"one", "washi":"testing", "monk":"lasth"])]
ViewArray += [CTArray(ctname: "techiu", ctkey: "TCU", ctC: ["22":"tt", "wke":"303", "lenth":"highest"])]
i want to show them in my TableView Cell sorted like these:
the ViewArray[0].ctC.key sorted like [mon, kis, Bat, orlno]
the ViewArray[1].ctC.key sorted like [letGor, washi, monk]
the ViewArray[2].ctC.value sorted like [tt, 303, highest]
It is not clear to me what you are asking, but I'll offer this in case it helps.
I know the Dictionary is not stored sequence like an Array and that is my problem.
If you want to access a dictionary by a certain order of its keys then you can create an array of just the keys in the order you required and use that to access the dictionary. An example is probably easier to follow:
Starting with one of your dictionaries:
let dict = ["mon":"Apple", "kis":"aone", "Bat":"Best", "orlno":"bOne"]
print(dict)
this output:
["Bat": "Best", "kis": "aone", "orlno": "bOne", "mon": "Apple"]
which is not what you want. Now introduce a key array and use that to access the dictionary:
let keyOrder = ["mon", "kis", "Bat", "orlno"]
for key in keyOrder
{
print("\(key): \(dict[key]!)")
}
this outputs:
mon: Apple
kis: aone
Bat: Best
orlno: bOne
which is the order you wish.
The same idea can be used anywhere you want to use/show/etc. the keys in a particular order, by using the keyOrder array as part of dictionary access you are making it appear as though the dictionary entries are "stored in sequence" as you put it.
HTH
var object1 = viewArray[0].ctC.flatMap({$0.key})
var object2 = viewArray[1].ctC.flatMap({$0.key})
var object3 = viewArray[2].ctC.flatMap({$0.value})
print(object1)
print(object2)
print(object3)
Outputs:
["Bat", "kis", "orlno", "mon"]
["letGor", "monk", "washi"]
["highest", "tt", "303"]

getting specific object in fetchedObjects without iteration

My app has a custom object SSSchedule that I persist in CoreData, with a sortDescriptor of "date" (SSSchedule has a variable var date : NSDate?). Is there a more efficient method to finding a specific SSSchedule object with a specific date rather than iterating through the fetchedObjects array checking each for schedule.date == myDate as! NSDate?
My app references the fetchedObjects quite often, so I would imagine constantly mapping fetchedObjects to a dictionary of type [String : SSSchedule] (for example) every time the context is saved would affect performance...
Write a fetch request to return the objects matching that specific date from the datastore. If you are being consistent, then from what you've written you'll get back an array with one element.
Let Core Data do that searching for you. That's what it's for.
I think if you use a plist which has a Dictionary of Dictionaries. it could be a more what you need.
The first Dictionary will have a key of a tuple of (Day,Month,Year) which can be easily extracted from NSDate. and a value of a Dictionary which key is a tuple of (Hours, Minutes) also extracted from NSDate and a value of String which is the task to do at that time.
this way if you have a specific date, that date is the key to access only the tasks and events you have during that specific date in O(1) time complexity.
Now if you want to know if you have something at a specific time you access it in a similar way. The method is supposed to return String?. If there's a task at a specific time, it will return the task, otherwise it will return nil which means you're free at this time.
This is how the data structure should look [(Day, Month,Year):[(Hours,Minutes):String]]
Regarding extracting components from NSDate
let date = NSDate()
let calendar = NSCalendar.currentCalendar()
let components = calendar.components(.CalendarUnitHour |.CalendarUnitMinute
|.CalendarUnitYear|.CalendarUnitMonth|.CalendarUnitDay, fromDate: date)
let day = components.day
let month = components.month
let year = compononets.year
let hour = components.hour
let minutes = components.minutes
Use filter() to build a new array with any objects that match your criteria:
let newArray = fetchedObjects.filter() { $0.date == myDate as! NSDate }
Then check the count of newArray and handle accordingly - unless you know the dates are unique, there could be zero, one or more elements in the array.

Get the object with the most recent date

I have an array of objects of type Thing:
class Thing: NSObject {
var data: String
var type: String
var created: NSDate
}
These things have an NSDate property called created. My aim is to write a function that reads the created property of every thing in the array and returns the thing that has the most recent date. The function looks like this:
public func getLastSwipe(list: Array<Thing>) -> Thing {
return someThing
}
Another approach is using Swift's .max, like this:
dates.max(by: <)
The following is my old answer. The above is updated in feb 2023.
let mostRecentDate = dates.max(by: {
$0.timeIntervalSinceReferenceDate < $1.timeIntervalSinceReferenceDate
})
This is the most performant solution I've found.
Returns the sequence’s most recent date if the sequence is not empty; otherwise, nil.
You could use reduce if you wanted. This will find the object with the highest timestamp.
var mostRecent = list.reduce(list[0], { $0.created.timeIntervalSince1970 > $1.created.timeIntervalSince1970 ? $0 : $1 } )
If your dates are not all in the past, you'll have to also compare against the current date to determine a cutoff. If your dates are all in the future, you'll want to switch the > to < to find the next future date (lowest timestamp).
You can sort the array, then find the first/last element. For example...
let objects: [Thing] = ... //Set the array
let mostResent = array.sorted { (firstThing, secondThing) -> Bool in
firstThing.created.timeIntervalSince1970 > secondThing.created.timeIntervalSince1970
}.first
This will return the most resent Thing as an Optional (because there is no guarantee that the array is not empty. If you know that the array is not empty, then you can end that line with .first!

Resources