如何使用一个数组作为另一个数组的谓词?
NSArray *arrClient = [[NSArray alloc] initWithObjects:@"record 1", @"record 2", nil];
NSArray *arrServer = [[NSArray alloc] initWithObjects:@"record 1", @"record 3", nil];
对arrServer
我想应用谓词来仅筛选那些在arrClient
中不存在的条目。例如在这种情况下,record 1
存在于两个数组中,并且应该被忽略,因此只有具有“记录3”字符串的条目的数组才会被返回。如何使用一个数组作为另一个数组的谓词?
这可能吗?下面
UPDATE
的答案是伟大的。我相信我需要举一个真实的例子来验证我所做的事情是否有意义。 (我仍然给下面的压缩版本)
现在clientItems将类型FTRecord(核心数据)的
@interface FTRecord : NSManagedObject
...
@property (nonatomic) NSTimeInterval recordDate;
@end
@implementation FTRecord
...
@dynamic recordDate;
@end
下面这个类是从一个REST服务解析JSON的支架。因此,我们前面提到的serverItems将是这种类型的。
@interface FTjsonRecord : NSObject <JSONSerializable>
{
}
@property (nonatomic) NSDate *recordDate;
@implementation FTjsonRecord
- (NSUInteger)hash
{
return [[self recordDate] hash];
}
- (BOOL)isEqual:(id)object
{
if ([object isKindOfClass:[FTjsonRecord self]]) {
FTjsonRecord *other = object;
return [[self recordDate] isEqualToDate:[other recordDate]];
}
else if ([object isKindOfClass:[FTRecord self]]) {
FTRecord *other = object;
return [[self recordDate] isEqualToDate:[NSDate dateWithTimeIntervalSinceReferenceDate:[other recordDate]]];
}
else {
return NO;
}
}
与Wain的例子一起,这似乎工作正常。现在可行吗? 请记住,serverItems只是临时的,仅用于与服务器同步,并将被丢弃。 clientItems是一个仍然存在的地方。
更新2:
这一次,我想马努的解决方案:
我建立了我的客户DBStore,这是由谓词调用此方法。 我不能使用containsObject
的原因是因为serverItems和clientItems中的类类型不是同一类型。
-(BOOL)recordExistsForDate:(NSDate *)date
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"recordDate == %@", date];
NSArray *arr = [allRecords filteredArrayUsingPredicate:predicate];
if (arr && [arr count] > 0) {
return YES;
} else {
return NO;
}
}
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(FTjsonRecord *evaluatedObject, NSDictionary *bindings) {
return ![store recordExistsForDate:[evaluatedObject recordDate]];
}];
NSSet *set = [[serverRecords items] filteredSetUsingPredicate:predicate];
我担心这个解决方案虽然是从我clientItems(allRecords)读取线性。我不确定它是如何有效地使用数组上的谓词,想知道是否有更好的方法来实现这一点。
依赖于您要使用的谓词:
可以在阵列
或使用在使用本
[NSPredicate predicateWithFormat:<#(NSString *)#> argumentArray:<#(NSArray *)#>];
使用的参数数组,并建立一个使用对象的谓词一个带谓词的块
[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
<#code#>
}]
并且在该块中形成ob JECT与对象比较其阵列中
可能的检查,你可以做的是:
return ![arrClient containsObject:evaluatedObject];
将排除包含在arrClient
containsObject对象:使用“isEqual:方法”来比较的对象
您可以使用NSSet
获得其他集合的联合,相交和差异(减号)。这更准确地匹配你想要做的事情。
NSMutableSet *serverItems = [[NSMutableSet alloc] init];
[arrServerItems addObjectsFromArray:arrServer];
NSSet *clientItems = [[NSSet alloc] init];
[clientItems addObjectsFromArray:arrClient];
[arrServerItems minus:clientItems];
虽然这不会删除订购信息。
谓词可以使用:
NSPredicate *filterPredicate = [NSPredicate predicateWithFormat:@"NOT (SELF IN %@)", arrClient];
谢谢,这看起来非常好。现在我的serverItems和clientItems碰巧有不同的类型。在这种情况下,我需要在serverItem类型上实现'isEqual'以使'minusSet'工作正确吗? – Houman
是的,但没有。你真的应该在你的问题中给出一个真实的例子。如果你把东西放在集合中,你不想改变'isEqual'。您最好使用自定义比较方法,并根据@Manu答案使用'predicateWithBlock'。 – Wain
Mhh有趣。我确实得到了它的工作。你提到,但我不应该这样做。我现在用真实的例子更新了这个问题。请你看看它是否有意义,或者我太过分了? – Houman
你看着使用'NSSet'而不是谓词? – Wain
你能举个例子吗? – Houman