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

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

有更好的方法吗?

有帮助吗?

解决方案

NSArray NSMutableArray 提供了过滤数组内容的方法。 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" }

其他提示

有很多方法可以做到这一点,但到目前为止,最好的肯定是使用 [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.
}]];

我认为这很简洁。


夫特:

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

nsArray = nsArray.filter { <*>.shouldIKeepYou() }
filter 只是 Array 上的一个方法( NSArray 隐式桥接到Swift&#8217; s Array )。它需要一个参数:一个闭包,它接受数组中的一个对象并返回 Bool 。在闭包中,只需为过滤后的数组中的任何对象返回 true

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

希望别人写这个类别,测试它等等?查看 BlocksKit 数组文档)。并且有很多更多的例子可供查找,例如搜索,例如“nsarray block category选取[。

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

yourArray = [yourArray objectsAtIndexes:[yourArray indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
    return [self testFunc:obj];
}]];

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

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

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

然后你将在哪里过滤:

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

当然,如果你的函数只对你的类中可以访问的属性进行比较,那么将函数的条件转换为谓词字符串可能会更容易。

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

例如,考虑两个数组 arr filteredarr

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

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

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

让人们很容易记住那些有小sql背景的人

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

1)从tbl中选择* - &gt;集合

2)column1喜欢'%a%' - &gt; NSPredicate * predicate = [NSPredicate predicateWithFormat:@&quot; SELF包含[c]%@&quot;,@&quot; c&quot;];

3)从tbl中选择*,其中column1类似'%a%' - &gt;

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

我希望这会有所帮助

<强>的NSArray + X.h

@interface NSArray (X)
/**
 *  @return new NSArray with objects, that passing test block
 */
- (NSArray *)filteredArrayPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate;
@end

<强>的NSArray + X.m

@implementation NSArray (X)

- (NSArray *)filteredArrayPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate
{
    return [self objectsAtIndexes:[self indexesOfObjectsPassingTest:predicate]];
}

@end

您可以在此处下载此类别

查看此库

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;
}];

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

- (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;
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top