Swift 字典扩展数组 sortInPlace
Swift Array of dictionaries extension sortInPlace
使用 Swift 2.1 我正在尝试创建一个函数,该函数按键 dateKey 的日期值对字典数组进行排序。
我想将它添加为 Array 类型的扩展,这样我就可以使用 someArray.sortDictionariesByDate(dateKey: String, dateFormatter: NSDateFormatter)
来调用它
extension Array where Element: CollectionType {
mutating func sortDictionariesByDate(dateKey: String, dateFormatter: NSDateFormatter) {
sortInPlace {
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
if let dateStringA: String = ([=11=] as? [String: AnyObject])?[dateKey] as? String, let dateStringB = ( as? [String: AnyObject])?[dateKey] as? String {
if let dateA: NSDate = dateFormatter.dateFromString(dateStringA), dateB: NSDate = dateFormatter.dateFromString(dateStringB) {
return dateA.compare(dateB) == .OrderedAscending
}
}
return false
}
}
}
只要字典的类型为 [String: AnyObject]
,它就可以正常工作,但是如果我在类型为 [String: String]
的字典上使用它,它就无法工作,因为它无法转换为 [=16] =] 到 AnyObject
。我认为这是因为 String
是 Struct
而不是 Class
。我也尝试将元素类型转换为 [String: Any]
,但是无论使用 [String: AnyObject]
或 [String: String]
.
类型的字典,它都不会工作
是否有任何转换可以用来支持具有键类型 String
和任何值类型(String
、AnyObject
等)的字典,或者可能是 where 子句或协议可以添加到扩展中以避免完全转换的一致性?
编辑:这是根据请求
的两个示例数组
var sampleArray1: [[String: AnyObject]] = [["date": "2015-10-24T13:00:00.000Z", "foo": "bar"], ["date": "2015-10-24T14:00:00.000Z", "foo": "bar"]]
sampleArray1.sortDictionariesByDate("date", dateFormatter: NSDateFormatter())
var sampleArray2: [[String: String]] = [["date": "2015-10-24T13:00:00.000Z", "foo": "bar"], ["date": "2015-10-24T14:00:00.000Z", "foo": "bar"]]
sampleArray2.sortDictionariesByDate("date", dateFormatter: NSDateFormatter())
第一个问题:您比较的是字符串,而不是日期。幸运的是,您的字符串格式使其可以直接与字符串及其表示的日期值进行比较。因此,您根本不需要将其转换为 NSDate
。
第二个问题是将 Dictionary<Key,Value1>
类型转换为 Dictionary<Key,Value2>
批发不起作用,即使 Value1
在 Value2
上是 covariant 也是如此。它可能在像这样的小例子中工作...
let a : [String: String] = ["name": "David", "location": "Chicago"]
let b = a as [String: AnyObject]
...因为编译器可以看到a
中的值类型(String
)并通过编译时优化。对于像您这样的动态情况,无法提前提供信息。
当你需要活力的时候,总能回到老朋友身边,Objective-C:
extension Array where Element: CollectionType {
mutating func sortDictionariesByDate(dateKey: String) {
self.sortInPlace {
if let a = [=11=] as? NSDictionary, b = as? NSDictionary {
return (a[dateKey] as? String) < (b[dateKey] as? String)
} else {
return false
}
}
}
}
// Example:
var sampleArray1: [[String: AnyObject]] = [
["date": "2015-10-24T13:00:00.000Z", "foo": "bar"],
["date": "2015-10-24T14:00:00.000Z", "foo": "bar"],
["date": "2015-10-24T10:00:00.000Z", "foo": "bar"]
]
var sampleArray2: [[String: String]] = [
["date": "2015-10-24T13:00:00.000Z", "foo": "bar"],
["date": "2015-10-24T14:00:00.000Z", "foo": "bar"],
["date": "2015-10-24T10:00:00.000Z", "foo": "bar"]
]
sampleArray1.sortDictionariesByDate("date")
sampleArray2.sortDictionariesByDate("date")
请注意,由于您现在比较的是字符串而不是日期,因此不需要 NSDateFormatter
。
你要求做的事很愚蠢。您不会编写一个不强制转换就同时适用于 [[String:AnyObject]]
和 [[String:String]]
的函数。 Swift 有严格的类型。就是这样。铸造并快乐!
像字典一样转换复杂类型数组的技巧是使用 map
单独转换每个元素(这实际上是数组转换在幕后所做的):
let sampleArray1: [[String: AnyObject]] = [["date": "2015-10-24T13:00:00.000Z", "foo": "bar"], ["date": "2015-10-24T14:00:00.000Z", "foo": "bar"]]
let sampleArray2: [[String: String]] = [["date": "2015-10-24T13:00:00.000Z", "foo": "bar"], ["date": "2015-10-24T14:00:00.000Z", "foo": "bar"]]
func sortByDate(arr:[[String:AnyObject]]) -> [[String:AnyObject]] {
let result = arr.sort {
d1, d2 in
let dat1 = NSDateFormatter().dateFromString(d1["date"] as! String)!
let dat2 = NSDateFormatter().dateFromString(d2["date"] as! String)!
return dat1.timeIntervalSinceReferenceDate < dat2.timeIntervalSinceReferenceDate
}
return result
}
let arr1 = sortByDate(sampleArray1)
let arr2 = sortByDate(sampleArray2.map{[=10=] as [String:AnyObject]})
// and if you have to, `map` arr2 back down to [String:String]
我承认我没有完全填写规范,但是添加更多参数很容易,这样您就可以提供键名和格式化程序。请注意,该示例实际上 在您的数据上崩溃 因为我们没有匹配的日期格式。您需要提供有效的格式。
我也认为(作为同一点的一部分)将日期字符串而不是实际日期放入字典是愚蠢的。但我只是为了争论才同意这个前提。
这是一个不同的解决方案,它在处理函数内的转换时将函数保留为 Array
的扩展,从而避免在处理不同类型的字典时来回使用 .map()
.缺点是你必须提前知道函数支持的类型,而@matt 的解决方案允许你在调用方法时处理转换,但代价是不是扩展,不是原地排序和映射回来和第四。
extension Array where Element: CollectionType {
mutating func sortDictionariesByDate(dateKey: String, dateFormatter: NSDateFormatter) {
sortInPlace {
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
var dateString1: String?
var dateString2: String?
if let a = [=10=] as? [String: AnyObject], let b = as? [String: AnyObject] {
if let dateStringA: String = a[dateKey] as? String, dateStringB: String = b[dateKey] as? String {
dateString1 = dateStringA
dateString2 = dateStringB
}
} else if let a = [=10=] as? [String: String], let b = as? [String: String] {
dateString1 = a[dateKey]
dateString2 = b[dateKey]
}
if let dateString1: String = dateString1, let dateString2: String = dateString2 {
if let date1: NSDate = dateFormatter.dateFromString(dateString1), date2: NSDate = dateFormatter.dateFromString(dateString2) {
return date1.timeIntervalSinceReferenceDate < date2.timeIntervalSinceReferenceDate
}
}
return false
}
}
}
// Example:
var sampleArray1: [[String: AnyObject]] = [
["date": "2015-10-24T13:00:00.000Z", "foo": "bar"],
["date": "2015-10-24T14:00:00.000Z", "foo": "bar"],
["date": "2015-10-24T10:00:00.000Z", "foo": "bar"]
]
var sampleArray2: [[String: String]] = [
["date": "2015-10-24T13:00:00.000Z", "foo": "bar"],
["date": "2015-10-24T14:00:00.000Z", "foo": "bar"],
["date": "2015-10-24T10:00:00.000Z", "foo": "bar"]
]
sampleArray1.sortDictionariesByDate("date")
sampleArray2.sortDictionariesByDate("date")
使用 Swift 2.1 我正在尝试创建一个函数,该函数按键 dateKey 的日期值对字典数组进行排序。
我想将它添加为 Array 类型的扩展,这样我就可以使用 someArray.sortDictionariesByDate(dateKey: String, dateFormatter: NSDateFormatter)
extension Array where Element: CollectionType {
mutating func sortDictionariesByDate(dateKey: String, dateFormatter: NSDateFormatter) {
sortInPlace {
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
if let dateStringA: String = ([=11=] as? [String: AnyObject])?[dateKey] as? String, let dateStringB = ( as? [String: AnyObject])?[dateKey] as? String {
if let dateA: NSDate = dateFormatter.dateFromString(dateStringA), dateB: NSDate = dateFormatter.dateFromString(dateStringB) {
return dateA.compare(dateB) == .OrderedAscending
}
}
return false
}
}
}
只要字典的类型为 [String: AnyObject]
,它就可以正常工作,但是如果我在类型为 [String: String]
的字典上使用它,它就无法工作,因为它无法转换为 [=16] =] 到 AnyObject
。我认为这是因为 String
是 Struct
而不是 Class
。我也尝试将元素类型转换为 [String: Any]
,但是无论使用 [String: AnyObject]
或 [String: String]
.
是否有任何转换可以用来支持具有键类型 String
和任何值类型(String
、AnyObject
等)的字典,或者可能是 where 子句或协议可以添加到扩展中以避免完全转换的一致性?
编辑:这是根据请求
的两个示例数组var sampleArray1: [[String: AnyObject]] = [["date": "2015-10-24T13:00:00.000Z", "foo": "bar"], ["date": "2015-10-24T14:00:00.000Z", "foo": "bar"]]
sampleArray1.sortDictionariesByDate("date", dateFormatter: NSDateFormatter())
var sampleArray2: [[String: String]] = [["date": "2015-10-24T13:00:00.000Z", "foo": "bar"], ["date": "2015-10-24T14:00:00.000Z", "foo": "bar"]]
sampleArray2.sortDictionariesByDate("date", dateFormatter: NSDateFormatter())
第一个问题:您比较的是字符串,而不是日期。幸运的是,您的字符串格式使其可以直接与字符串及其表示的日期值进行比较。因此,您根本不需要将其转换为 NSDate
。
第二个问题是将 Dictionary<Key,Value1>
类型转换为 Dictionary<Key,Value2>
批发不起作用,即使 Value1
在 Value2
上是 covariant 也是如此。它可能在像这样的小例子中工作...
let a : [String: String] = ["name": "David", "location": "Chicago"]
let b = a as [String: AnyObject]
...因为编译器可以看到a
中的值类型(String
)并通过编译时优化。对于像您这样的动态情况,无法提前提供信息。
当你需要活力的时候,总能回到老朋友身边,Objective-C:
extension Array where Element: CollectionType {
mutating func sortDictionariesByDate(dateKey: String) {
self.sortInPlace {
if let a = [=11=] as? NSDictionary, b = as? NSDictionary {
return (a[dateKey] as? String) < (b[dateKey] as? String)
} else {
return false
}
}
}
}
// Example:
var sampleArray1: [[String: AnyObject]] = [
["date": "2015-10-24T13:00:00.000Z", "foo": "bar"],
["date": "2015-10-24T14:00:00.000Z", "foo": "bar"],
["date": "2015-10-24T10:00:00.000Z", "foo": "bar"]
]
var sampleArray2: [[String: String]] = [
["date": "2015-10-24T13:00:00.000Z", "foo": "bar"],
["date": "2015-10-24T14:00:00.000Z", "foo": "bar"],
["date": "2015-10-24T10:00:00.000Z", "foo": "bar"]
]
sampleArray1.sortDictionariesByDate("date")
sampleArray2.sortDictionariesByDate("date")
请注意,由于您现在比较的是字符串而不是日期,因此不需要 NSDateFormatter
。
你要求做的事很愚蠢。您不会编写一个不强制转换就同时适用于 [[String:AnyObject]]
和 [[String:String]]
的函数。 Swift 有严格的类型。就是这样。铸造并快乐!
像字典一样转换复杂类型数组的技巧是使用 map
单独转换每个元素(这实际上是数组转换在幕后所做的):
let sampleArray1: [[String: AnyObject]] = [["date": "2015-10-24T13:00:00.000Z", "foo": "bar"], ["date": "2015-10-24T14:00:00.000Z", "foo": "bar"]]
let sampleArray2: [[String: String]] = [["date": "2015-10-24T13:00:00.000Z", "foo": "bar"], ["date": "2015-10-24T14:00:00.000Z", "foo": "bar"]]
func sortByDate(arr:[[String:AnyObject]]) -> [[String:AnyObject]] {
let result = arr.sort {
d1, d2 in
let dat1 = NSDateFormatter().dateFromString(d1["date"] as! String)!
let dat2 = NSDateFormatter().dateFromString(d2["date"] as! String)!
return dat1.timeIntervalSinceReferenceDate < dat2.timeIntervalSinceReferenceDate
}
return result
}
let arr1 = sortByDate(sampleArray1)
let arr2 = sortByDate(sampleArray2.map{[=10=] as [String:AnyObject]})
// and if you have to, `map` arr2 back down to [String:String]
我承认我没有完全填写规范,但是添加更多参数很容易,这样您就可以提供键名和格式化程序。请注意,该示例实际上 在您的数据上崩溃 因为我们没有匹配的日期格式。您需要提供有效的格式。
我也认为(作为同一点的一部分)将日期字符串而不是实际日期放入字典是愚蠢的。但我只是为了争论才同意这个前提。
这是一个不同的解决方案,它在处理函数内的转换时将函数保留为 Array
的扩展,从而避免在处理不同类型的字典时来回使用 .map()
.缺点是你必须提前知道函数支持的类型,而@matt 的解决方案允许你在调用方法时处理转换,但代价是不是扩展,不是原地排序和映射回来和第四。
extension Array where Element: CollectionType {
mutating func sortDictionariesByDate(dateKey: String, dateFormatter: NSDateFormatter) {
sortInPlace {
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
var dateString1: String?
var dateString2: String?
if let a = [=10=] as? [String: AnyObject], let b = as? [String: AnyObject] {
if let dateStringA: String = a[dateKey] as? String, dateStringB: String = b[dateKey] as? String {
dateString1 = dateStringA
dateString2 = dateStringB
}
} else if let a = [=10=] as? [String: String], let b = as? [String: String] {
dateString1 = a[dateKey]
dateString2 = b[dateKey]
}
if let dateString1: String = dateString1, let dateString2: String = dateString2 {
if let date1: NSDate = dateFormatter.dateFromString(dateString1), date2: NSDate = dateFormatter.dateFromString(dateString2) {
return date1.timeIntervalSinceReferenceDate < date2.timeIntervalSinceReferenceDate
}
}
return false
}
}
}
// Example:
var sampleArray1: [[String: AnyObject]] = [
["date": "2015-10-24T13:00:00.000Z", "foo": "bar"],
["date": "2015-10-24T14:00:00.000Z", "foo": "bar"],
["date": "2015-10-24T10:00:00.000Z", "foo": "bar"]
]
var sampleArray2: [[String: String]] = [
["date": "2015-10-24T13:00:00.000Z", "foo": "bar"],
["date": "2015-10-24T14:00:00.000Z", "foo": "bar"],
["date": "2015-10-24T10:00:00.000Z", "foo": "bar"]
]
sampleArray1.sortDictionariesByDate("date")
sampleArray2.sortDictionariesByDate("date")