125

我有一个NSArray,我想NSArray用原始数组中满足特定条件的对象创建一个新对象。条件由返回 a 的函数决定BOOL

我可以创建一个NSMutableArray, 遍历源数组并复制过滤器函数接受的对象,然后创建它的不可变版本。

有没有更好的办法?

4

9 回答 9

144

NSArrayNSMutableArray提供过滤数组内容的方法。NSArray提供filteredArrayUsingPredicate:它返回一个新数组,其中包含接收器中与指定谓词匹配的对象。NSMutableArray添加filterUsingPredicate:它根据指定的谓词评估接收者的内容并只留下匹配的对象。这些方法在以下示例中进行了说明。

NSMutableArray *array =
    [NSMutableArray arrayWithObjects:@"Bill", @"Ben", @"Chris", @"Melissa", nil];

NSPredicate *bPredicate =
    [NSPredicate predicateWithFormat:@"SELF beginswith[c] 'b'"];
NSArray *beginWithB =
    [array filteredArrayUsingPredicate:bPredicate];
// beginWithB contains { @"Bill", @"Ben" }.

NSPredicate *sPredicate =
    [NSPredicate predicateWithFormat:@"SELF contains[c] 's'"];
[array filteredArrayUsingPredicate:sPredicate];
// array now contains { @"Chris", @"Melissa" }
于 2008-09-21T05:43:47.087 回答
116

有很多方法可以做到这一点,但到目前为止,最简洁的方法肯定是使用[NSPredicate predicateWithBlock:]

NSArray *filteredArray = [array filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id object, NSDictionary *bindings) {
    return [object shouldIKeepYou];  // Return YES for each object you want in filteredArray.
}]];

我认为这是尽可能简洁。


迅速:

对于那些NSArray在 Swift 中使用 s 的人,你可能更喜欢这个简洁的版本:

let filteredArray = array.filter { $0.shouldIKeepYou() }

filter只是一个方法ArrayNSArray隐式桥接到 Swift 的Array)。它接受一个参数:一个闭包,它接受数组中的一个对象并返回一个Bool. 在您的闭包中,只需true在过滤后的数组中返回您想要的任何对象。

于 2013-10-22T12:06:55.353 回答
50

根据 Clay Bridges 的回答,这是一个使用块进行过滤的示例(更改yourArray为您的数组变量名称和testFunc测试函数的名称):

yourArray = [yourArray objectsAtIndexes:[yourArray indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
    return [self testFunc:obj];
}]];
于 2012-11-08T12:14:23.347 回答
46

如果您是 OS X 10.6/iOS 4.0 或更高版本,那么使用块可能比使用 NSPredicate 更好。查看-[NSArray indexesOfObjectsPassingTest:]或编写您自己的类别以添加方便-select:-filter:方法(示例)。

希望其他人编写该类别,对其进行测试等?查看BlocksKit数组文档)。还有更多的例子可以通过搜索来找到,例如“nsarray block category select”

于 2010-10-04T16:22:44.910 回答
17

假设您的对象都是相似的类型,您可以添加一个方法作为其基类的一个类别,该类别调用您用于标准的函数。然后创建一个引用该方法的 NSPredicate 对象。

在某些类别中定义使用您的函数的方法

@implementation BaseClass (SomeCategory)
- (BOOL)myMethod {
    return someComparisonFunction(self, whatever);
}
@end

然后无论您要过滤:

- (NSArray *)myFilteredObjects {
    NSPredicate *pred = [NSPredicate predicateWithFormat:@"myMethod = TRUE"];
    return [myArray filteredArrayUsingPredicate:pred];
}

当然,如果您的函数仅与类中可访问的属性进行比较,则将函数的条件转换为谓词字符串可能会更容易。

于 2008-11-21T07:17:39.610 回答
3

NSPredicate是 nextstep 构造条件以过滤集合 ( NSArray, NSSet, NSDictionary) 的方式。

例如考虑两个数组arrfilteredarr

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF contains[c] %@",@"c"];

filteredarr = [NSMutableArray arrayWithArray:[arr filteredArrayUsingPredicate:predicate]];

filterdarr 肯定会包含仅包含字符 c 的项目。

方便记住那些很少有sql背景的人

*--select * from tbl where column1 like '%a%'--*

1) 从 tbl 中选择 * --> 集合

2)column1 like '%a%' -->NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF contains[c] %@",@"c"];

3)select * from tbl where column1 like '%a%' -->

[NSMutableArray arrayWithArray:[arr filteredArrayUsingPredicate:predicate]];

我希望这有帮助

于 2013-04-04T10:51:50.977 回答
0

签出这个库

https://github.com/BadChoice/Collection

它带有许多简单的数组函数,再也不用写循环了

所以你可以这样做:

NSArray* youngHeroes = [self.heroes filter:^BOOL(Hero *object) {
    return object.age.intValue < 20;
}];

或者

NSArray* oldHeroes = [self.heroes reject:^BOOL(Hero *object) {
    return object.age.intValue < 20;
}];
于 2016-08-29T17:56:03.703 回答
0

最好和最简单的方法是创建这个方法并传递数组和值:

- (NSArray *) filter:(NSArray *)array where:(NSString *)key is:(id)value{
    NSMutableArray *temArr=[[NSMutableArray alloc] init];
    for(NSDictionary *dic in self)
        if([dic[key] isEqual:value])
            [temArr addObject:dic];
    return temArr;
}
于 2018-11-20T01:39:36.210 回答
0

您可以使用的另一种分类方法:

- (NSArray *) filteredArrayUsingBlock:(BOOL (^)(id obj))block {
    NSIndexSet *const filteredIndexes = [self indexesOfObjectsPassingTest:^BOOL (id _Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
                                       return block(obj);
                                   }];

    return [self objectsAtIndexes:filteredIndexes];
}
于 2021-01-18T02:07:49.097 回答