问题
I am creating an application with separate posts in it (similar to Instagram). Each post is a dictionary located in one big array. Within each dictionary their is an NSDate which I would like to sort the dictionaries by in order from newest to oldest.
I have read similar questions but they are in objective C. I have a feeling NSSortDescriptor
be a helpful method but am unsure on how to use it in this situation.
Any help would be great,
Thanks
回答1:
If you’re writing in Swift, you’ll probably find it easier to use the Swift array type ([ContainedType]
) than NSArray
. Amongst other things, sorting Swift arrays is more straightforward than having to use NSSortDescriptor
etc.
NSDates can be compared using .compare
like so:
let d1 = NSDate()
let d2 = NSDate()
d1.compare(d2) == .OrderedAscending
But you might prefer them to implement the Comparable
protocol, which can be done like this:
extension NSDate: Comparable { }
public func ==(lhs: NSDate, rhs: NSDate) -> Bool {
return lhs.isEqualToDate(rhs)
}
public func <(lhs: NSDate, rhs: NSDate) -> Bool {
return lhs.compare(rhs) == .OrderedAscending
}
// now you can do
d1 > d2
d1 <= d2 //etc
With this, you can sort arrays of dates:
let arr = [d2, d1]
let sortedArr = arr.sorted(<) // or > for descending order
If you had dictionaries of dates, you would need to fetch the date value out dictionary and compare it, but that’s easy:
let dicts = [["Date":d2], ["Date":d1]]
// pass sorted a function that compares two candidates in the array
dicts.sorted { lhs, rhs in
// even though dictionary lookups return optionals,
// this is fine because < is defined for optionals of Comparables
// (nil is < anything else)
lhs["Date"] < (rhs["Date"]
}
Except… chances aren’t that you actually have an array of [String:NSDate]
– you probably have a bunch of different types in there and its actually a [String:AnyObject]
, so you need to convert the type:
// dictionaries contain various different kind of values
let dicts: [[String:AnyObject]] = [["Date":d2], ["Date":d1]]
dicts.sorted { lhs, rhs in
(lhs["Date"] as? NSDate) < (rhs["Date"] as? NSDate)
}
But that said, you probably at this point want to think about storing your data not as a dictionary of stuff, but as a proper data structure:
struct Post {
let timestamp: NSDate
// and various other properties...
}
let posts: [Post] = [
Post(timestamp: d1),
Post(timestamp: d2)
]
posts.sorted { $0.timestamp < $1.timestamp }
EDIT: your comment mentions that you actually have a dictionary of type [String:String]
. This means you need to convert the strings to dates somehow before comparing them. In which case, you could use NSDateFormatter
to convert as part of the comparison. Some example code:
let dicts: [[String:String]] = [["Date":"May 20 20015"], ["Date":"May 20 2014"]]
let fmt = NSDateFormatter()
fmt.dateStyle = .MediumStyle
let sortedDicts = dicts.sorted { lhs, rhs in
lhs["Date"].flatMap(fmt.dateFromString) < rhs["Date"].flatMap(fmt.dateFromString)
}
So, when doing the comparison, fetch the date string out, then convert it to a NSDate
using the formatter, then compare the result.
Note, this uses flatMap
– this is because dateFromString
itself returns an optional, and you don’t want an optional-optional so you need to flatten the result.
The big downside to this is there’s no detection of invalid dates. If you got a date in there that was a bad format (say, month and day in the wrong order), dateFromString
would return nil
and it’d get sorted towards the start of the array.
The other downside of this is it’s getting pretty horribly inefficient. You may well be better off converting your data to more structured form (e.g. a struct
with an NSDate
-typed member variable) before doing this kind of processing.
来源:https://stackoverflow.com/questions/29455824/sort-array-of-dictionaries-by-nsdates-within-the-dictionaries