使用谓词基于另一个数组过滤NSArray

时间:2015-01-07 02:04:31

标签: ios objective-c predicate

考虑下面的数组。这些数组包含' Alpha'类型的对象。我们只关心username类型的属性NSString

NSArray *some_usernames = @[ <multiple values of type Alpha> ]
NSArray *all_usernames = @[ <multiple values of type Alpha> ]

我基本上想要一个不在数组some_usernames中的所有用户名的列表,即

NSArray *remaining_usernames = @[ <all_usernames but not in some_usernames> ];

我打算做的方式是:

NSPredicates *predicates;
for (Alpha *alpha in some_usernames)
{
    predicate = [predicate with @"username != %@", alpha.username];
    predicates.add(predicate)
}

create compound predicate
filter all_usernames

但这感觉就像这样做的坏方法。有两种方法可以做到这一点吗?我以前见过它,但我不能再指向代码引用了。

2 个答案:

答案 0 :(得分:13)

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"not (self.username IN %@)", [some_usernames valueForKey:@"username"]];
NSArray *remaining_usernames = [all_usernames filteredArrayUsingPredicate:predicate];

完整的例子

@interface Alpha : NSObject
@property (nonatomic, copy) NSString *username;
-(instancetype) initWithUsername:(NSString *)username;
@end

@implementation Alpha
-(instancetype) initWithUsername:(NSString *)username
{
    self = [super init];
    if (self) {
        self.username = username;
    }
    return self;
}

-(NSString *)description{
    return [NSString stringWithFormat:@"%@: %@", NSStringFromClass([self class]), self.username];
}
@end


NSArray *all_usernames = @[[[Alpha alloc] initWithUsername:@"a"], [[Alpha alloc] initWithUsername:@"b"], [[Alpha alloc] initWithUsername:@"z"], [[Alpha alloc] initWithUsername:@"f"], [[Alpha alloc] initWithUsername:@"e"]];
NSArray *some_usernames = @[[[Alpha alloc] initWithUsername:@"b"], [[Alpha alloc] initWithUsername:@"f"]];

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"not (self.username  IN %@)", [some_usernames valueForKey:@"username"]];
NSArray *remaining_usernames = [all_usernames filteredArrayUsingPredicate:predicate];

NSLog(@"%@", remaining_usernames);

打印

(
    "Alpha: a",
    "Alpha: z",
    "Alpha: e"
)

答案 1 :(得分:1)

我想补充一点:

如果不需要对象的排序(并且 - 很可能 - 不需要相等的对象),您可以使用集合并设置算术而不是对数组使用谓词过滤。为此,我们必须教Alpha什么是平等意味着什么并提供哈希方法。在这种情况下,我们只使用NSStrings实现:

@implementation Alpha
-(instancetype) initWithUsername:(NSString *)username
{
    self = [super init];
    if (self) {
        self.username = username;
    }
    return self;
}

-(NSString *)description{
    return [NSString stringWithFormat:@"%@: %@", NSStringFromClass([self class]), self.username];
}

-(BOOL)isEqual:(id)object
{
    return [self.username isEqual:[object username]];
}

-(NSUInteger)hash
{
    return [self.username hash];
}

@end



NSArray *all_usernames = @[[[Alpha alloc] initWithUsername:@"a"],
                           [[Alpha alloc] initWithUsername:@"b"],
                           [[Alpha alloc] initWithUsername:@"z"],
                           [[Alpha alloc] initWithUsername:@"f"],
                           [[Alpha alloc] initWithUsername:@"e"]];

NSArray *some_usernames = @[[[Alpha alloc] initWithUsername:@"b"],
                            [[Alpha alloc] initWithUsername:@"f"]];

NSSet *allSet = [NSSet setWithArray:all_usernames];
NSSet *someSet = [NSSet setWithArray:some_usernames];

NSMutableSet *remainingSet = [allSet mutableCopy];
[remainingSet minusSet:someSet];

NSLog(@"%@", remainingSet);

打印

{(
    Alpha: z,
    Alpha: e,
    Alpha: a
)}

对于更多数据,此代码应该更快。请观看WWDC 2013: Designing Code for Performance