在我的模型中,我有一个Car实体。
汽车 年 CREATEDATE 名称
我想运行一个fetch,每年返回所有最近的汽车名称不是nil(名称可以是nil)。
所以,如果我拥有3辆车,2000年和5辆汽车,2010年,我想从获取请求中获得总共2辆汽车(2000年的最新车型和2010年的最新车型)。
我不确定如何编写正确的谓词来实现这一点。我查看了returnsDistinctResults选项,但我不确定这是正确的路径下去它还说它只适用于NSDictionaryResultType,这对我不起作用。
完成此操作的正确查询/谓词是什么?
答案 0 :(得分:1)
使用算法简单地在每条记录上运行会更好。
允许您的Car类,定义以下内容。
struct C {
var year: Int
var created: Date
var name: String?
}
var cars = [C(year: 2009, created: Date(), name: nil), C(year: 2009, created: Date(), name: "Green"), C(year: 2010, created: Date(), name: "Green"), C(year: 2010, created: Date(), name: "Orange"), C(year: 2010, created: Date(), name: "Orange")]
var carsPerYear = [Int: [String: Int]]()
for car in cars {
if let name = car.name {
var info: [String: Int]? = nil
if carsPerYear.keys.contains(car.year) {
info = carsPerYear[car.year]
} else {
info = [String: Int]()
}
if !info!.keys.contains(name) {
info![name] = 0
}
info![name] = info![name]! + 1
carsPerYear[car.year] = info
}
}
for year in carsPerYear.keys {
let info = carsPerYear[year]!
let sorted = info.keys.sorted{ info[$0]! > info[$1]! }
print(year, sorted.first!)
}
提供输出
2009 Green
2010 Orange
有时SQL或CoreData无法轻松解决问题,最好只编写排序算法。
答案 1 :(得分:-1)
你可以实现这一点,如果说你将数年的数组传递给算法,并期望以字典的形式得到结果,每年你作为一个对应最多的对象的键传入那年的最近一辆车。
即:
let years : [Int] = [2000, 2005]
//The ideal method:
func mostRecentFor<T>(years: [Int]) -> [String:T]
假设您只使用少量搜索年,并且您的数据库拥有少量汽车,则不必担心线程问题。否则,对于这种方法,您必须使用并发或专用线程来获取,以避免阻塞主线程。出于测试目的,您不需要。
要实现此目的,您将使用沿着以下行的方法。
首先,应该像其他答案所建议的那样在年份上使用数字谓词。 为此,您将使用NSPredicate的日期格式:
NSPredicate(format: "date == %@", year)
因此,您的模型应将年份作为参数,将实际的nsdate作为另一个参数。然后,您可以将fecthLimit
参数设置为1,并将sortDescriptor
应用于nsDate键参数。后两者的组合将确保在给定年份仅返回最年轻或最旧的值。
func mostRecentFor(years: [Int]) -> [String:Car] {
let result : [String:Car] = [:]
for year in years {
let request: NSFetchRequest<CarModel> = CarModel.fetchRequest()
request.predicate = NSPredicate(format: "date == %@ AND name != nil", year)
request.fetchLimit = 1
let NSDateDescriptor: let sectionSortDescriptor = NSSortDescriptor(key: "nsDate", ascending: true)
let descriptors = [NSDateDescriptor]
fetchRequest.sortDescriptors = descriptors
do {
let fetched = try self.managedObjectContext.fetch(request) as
[CarModel]
guard !fetched.isEmpty, fetched.count == 1 else {
print("No Car For year: \(year)")
return
}
result["\(year)"] = new[0].resultingCarStruct //custom parameter here.. see bellow
} catch let err {
print("Error for Year: \(year), \(err.localizedDescription)")
}
}
return result
}
我们在这里使用升序集true
,因为我们希望第一个值(由于fetchLimit
值为1而实际返回的值)是该年度最早的汽车,或者一个时间戳最小的一个是nsDate密钥。
这应该为您提供一个简单的小数据存储和测试的获取查询。此外,创建一个方法或参数来将CarModel解释为它的Car struct对应物可以使从CD到内存对象更简单。
所以你要像这样搜索你的车:
let years = [1985, 1999, 2005]
let cars = mostRecentFor(years: years)
// cars = ["1985": Car<year: 1985, name: "Chevrolet", nsDate: "April 5th 1985">, "1999" : Car<year: 1999, name: "Toyota Corolla", nsDate: "February 5th 1999">]
// This examples suggests that no cars were found for 2005