Reputation: 3163
I have an array of CKRecords. Each record has startTime
and a Name
, among other values. What I would like to do is sort the records first by unique startTime
and then within each startTime sort by unique Name
.
The end result would be an array that looks like this (I think): records = [Date: [Name: [CKRecord]]]
Here is what I have right now:
func buildIndex(records: [CKRecord]) -> [[CKRecord]] {
var dates = [NSDate]()
var result = [[CKRecord]]()
for record in records {
var date = record.objectForKey("startTime") as! NSDate
if !contains(dates, date) {
dates.append(date)
}
}
for date in dates {
var recordForDate = [CKRecord]()
for (index, exercise) in enumerate(exercises) {
let created = exercise.objectForKey("startTime") as! NSDate
if date == created {
let record = exercises[index] as CKRecord
recordForDate.append(record)
}
}
result.append(recordForDate)
}
return result
}
let records = self.buildIndex(data)
Upvotes: 0
Views: 1704
Reputation: 13127
You could execute the CloudKit query and make sure that you get the array returned in the correct sort order like this:
query.sortDescriptors = [NSSortDescriptor(key: "startTime", ascending: true), NSSortDescriptor(key: "Name", ascending: true)]
And then if you go to the detail view, you could use the filter for getting the records for that day like this:
var details = records.filter { (%0.objectForKey("startTime") As! NSDate) == selectedDate }
Upvotes: 1
Reputation: 2193
Why not use sorted
? Like this.
// A simplified version of your `CKRecord` just for demonstration
struct Record {
let time: NSDate
let name: String
}
let records = [
Record(time: NSDate(timeIntervalSince1970: 1), name: "a"),
Record(time: NSDate(timeIntervalSince1970: 2), name: "b"),
Record(time: NSDate(timeIntervalSince1970: 1), name: "c"),
Record(time: NSDate(timeIntervalSince1970: 3), name: "d"),
Record(time: NSDate(timeIntervalSince1970: 3), name: "e"),
Record(time: NSDate(timeIntervalSince1970: 2), name: "f"),
]
func buildIndex(records: [Record]) -> [[Record]] {
var g = [NSDate: [Record]]()
for e in records {
if (g[e.time] == nil) {
g[e.time] = []
}
g[e.time]!.append(e) // grouping by `time`
}
return sorted(g.keys) { (a: NSDate, b: NSDate) in
a.compare(b) == .OrderedAscending // sorting the outer array by 'time'
}
// sorting the inner arrays by `name`
.map { sorted(g[$0]!) { $0.name < $1.name } }
}
println(buildIndex(records))
Upvotes: 2
Reputation: 12853
First of all, you're not really trying to sort an array here, you're trying to order a dictionary, which isn't built to be iterated over sequentially. In fact even if you do sort the array first and then build the dictionary like this:
var sortedRecords = [NSDate: [String: CKRecord]]()
records.sort { return $0.date.timeIntervalSinceDate($1.date) < 0 }
for record in records {
if sortedRecords[record.date] != nil {
sortedRecords[record.date] = [String: CKRecord]()
}
sortedRecords[record.date]![record.name] = record
}
The order isn't guaranteed when you iterate over it in the future. That said, a dictionary is essentially a look up table, and elements can be accessed in O(log n) time. What you'll really want to do is either drop the dictionary is favor of an array of [CKRecord]
and then sort like this:
records.sort { $0.date.timeIntervalSinceDate($1.date) == 0 ? $0.name < $1.name : $0.date.timeIntervalSinceDate($1.date) < 0 }
Or, depending on what your end goal is, iterate across a range of dates, plucking the entries from the dictionary as you go.
Upvotes: 2