通过属性过滤掉相似对象的谓词
Posted
技术标签:
【中文标题】通过属性过滤掉相似对象的谓词【英文标题】:a predicate to filter out similar objects by an attribute 【发布时间】:2013-06-25 20:20:48 【问题描述】:我正在执行一个没有任何谓词的常规 NSFetchRequest
来获取 100 个托管对象(航班),每个 Flight
实体都有一个名为 NSString
类型的属性(航班代码),这个属性不是唯一的,所以 2飞行对象可能具有相同的 flightCode 。
但是,我想获取所有航班对象,通过仅从相似之处采取一个航班来过滤掉具有相同航班代码的航班,即
如果 fetch 请求返回 5 个航班,如下所示:
flight1:flightCode = ABC
flight2:flightCode = AA
flight3: flightCode = ABC
flight4:flightCode = ABC
flight5:flightCode = DEF
那么获取请求必须过滤掉具有 flightCode ABC
的 3 个航班中的任意两个,并且只采用这 3 个中的任意一个。
此过滤所需的NSPredicate
是什么?
附言航班:1、3 和 4 在其他属性中可能不同,即航班 1 的名称可能与航班 3 的名称不同。
提前致谢。
【问题讨论】:
您是在寻找唯一的航班代码,还是希望从每组相同的航班代码中随机获得一个Flight
实例?
@BarryWark 我正在从每组相同的航班代码中寻找一个随机 Flight 实例。
我不认为你可以用NSFetchRequest
完成你想要的。您正在寻找的是分组操作的一些变体。在 Core Data 中,这必须在内存中完成。看起来您使用的是NSArrayController
。
@BarryWark 能否详细说明或显示一段代码?
【参考方案1】:
如果您只想要所有不同航班代码的列表,这可能会满足您的需求:
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Flight"
inManagedObjectContext:moc];
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:entity.name];
request.resultType = NSDictionaryResultType;
request.returnsDistinctResults = YES;
request.propertiesToFetch = @[ entity.propertiesByName[@"flightCode"] ];
请注意,returnsDistinctResults
仅在设置了 propertiesToFetch
时有效,propertiesToFetch
仅在 resultType
为 NSDictionaryResultType
时有效。
修订
如果您想要完整的 Flight
对象,但每个不同的航班代码只有一个,我认为您不能直接这样做。也许您可以同时要求对象 ID 和航班代码,按航班代码分组,并取最小对象 ID,以便为每个航班代码获取一个对象 ID。然后,您可以在托管对象上下文中使用 objectForID:
将这些对象 ID 一个一个地转换为完整对象。我会尝试这样的事情:
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Flight"
inManagedObjectContext:moc];
NSExpressionDescription *objectIDProperty = [[NSExpressionDescription alloc] init];
objectIDProperty.name = @"objectID";
objectIDProperty.expression = [NSExpression expressionForFunction:@"min:"
arguments:@[ [NSExpression expressedForEvaluatedObject] ]];
objectIdProperty.expressionResultType = NSObjectIDAttributeType;
NSAttributeDescription *flightCodeProperty = entity.propertiesByName[@"flightCode"];
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:entity.name];
request.resultType = NSDictionaryResultType;
request.returnsDistinctResults = YES;
request.propertiesToFetch = @[ flightCodeProperty, objectIDProperty ];
request.propertiesToGroupBy = @[ flightCodeProperty ];
我从this answer 那里抄袭了很多。我不知道它是否有效,或者我是否在正确的轨道上。如果它完全运行,但没有给出正确的输出,请记住,您可以通过添加 -com.apple.CoreData.SQLDebug 1
作为命令行参数来查看它正在执行的 SQL。
【讨论】:
我在 fetchedResultsController 中使用了这个 fetch 请求,我知道我会失去它的大部分功能(比如观察控制器的变化),但是如果可以的话,是否可以直接在 fetchedResultsController 中调用 objectForID ,如何? 据我所知,这是不可能的。您必须将objectIDProperty
的expressionResultType
设置为使其返回完整对象的东西,但there is no such type。
如果获取所有航班并在代码中过滤成本太高,您可能不得不对模型进行非规范化。例如,为Flight
实体提供一个名为flightCodeRepresentative
的布尔属性,并确保无论何时添加或删除航班,对于每个航班代码,只有一个航班将其设置为true。然后每个航班代码准确地获取一个航班变得微不足道。
使用 RestKit 映射器自动将航班保存到持久存储的问题,是的,使用代码过滤有点贵
您可以使用单个 NSFetchRequest
预填充缓存。缓存只是一个包含所有已知航班代码的NSMutableSet
(因为可能每个航班代码至少有一个航班)。插入新航班时,请检查缓存中的航班代码。如果缓存中缺少航班代码,请在新航班上将 flightCodeRepresentative
属性设置为 true 并将代码添加到缓存中。【参考方案2】:
您需要为所有航班创建一个 NSMuteableArray
,然后单独创建一个 NSMuteableArray
以跟踪您已经看到的元素
伪代码:
NSMuteablearray flights
NSMuteablearray alreadySeen
for (item in flights)
if (alreadySeen containsObject:item)
flights removeObject:item
else
alreadySeen addObject:item
【讨论】:
我不是在问objective-c 我是在问一个谓词,顺便说一句,获取请求将在一个fetchedResultsController getter中以上是关于通过属性过滤掉相似对象的谓词的主要内容,如果未能解决你的问题,请参考以下文章