如何使用一个数组作为另一个数组的谓词?

问题描述:

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)读取线性。我不确定它是如何有效地使用数组上的谓词,想知道是否有更好的方法来实现这一点。

+0

你看着使用'NSSet'而不是谓词? – Wain

+0

你能举个例子吗? – Houman

依赖于您要使用的谓词:

可以在阵列

或使用在使用本

[NSPredicate predicateWithFormat:<#(NSString *)#> argumentArray:<#(NSArray *)#>]; 

使用的参数数组,并建立一个使用对象的谓词一个带谓词的块

[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) { 
    <#code#> 
}] 

并且在该块中形成ob JECT与对象比较其阵列中

可能的检查,你可以做的是:

return ![arrClient containsObject:evaluatedObject]; 

将排除包含在arrClient

containsObject对象:使用“isEqual:方法”来比较的对象

+0

马努,如果你是如此善良的检查问题中的更新2,我将不胜感激。请记住,这两个数组不包含相同的类型。 (在更新1中更详细地提到)因此,我不能使用你建议的'containsObject'。所以我想知道我采取的这种方法是否好。我只关心性能。谢谢 – Houman

+0

在更新1中,你已经覆盖了hash和isEqual,所以即使对象是不同的类,你仍然可以使用containsObject(当然两个类都必须覆盖isEqual),或者你可以简单地在块中做同样的检查在做过的isEqual – Manu

您可以使用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]; 
+0

谢谢,这看起来非常好。现在我的serverItems和clientItems碰巧有不同的类型。在这种情况下,我需要在serverItem类型上实现'isEqual'以使'minusSet'工作正确吗? – Houman

+0

是的,但没有。你真的应该在你的问题中给出一个真实的例子。如果你把东西放在集合中,你不想改变'isEqual'。您最好使用自定义比较方法,并根据@Manu答案使用'predicateWithBlock'。 – Wain

+0

Mhh有趣。我确实得到了它的工作。你提到,但我不应该这样做。我现在用真实的例子更新了这个问题。请你看看它是否有意义,或者我太过分了? – Houman