题
我有一个 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;
}