将NSArray过滤到Objective-C中的新NSArray中
我有一个NSArray
,我想创build一个新的NSArray
与原始数组符合特定条件的对象。 标准由返回BOOL
的函数决定。
我可以创build一个NSMutableArray
,遍历源数组,并复制filter函数接受的对象,然后创build一个不可变的版本。
有没有更好的办法?
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 filterUsingPredicate: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 { $0.shouldIKeepYou() }
filter
只是一个Array
的方法( NSArray
隐式桥接到Swift的Array
)。 它有一个参数:一个闭包,它接受数组中的一个对象并返回一个Bool
。 在你的闭包中,只需要在过滤数组中的任何对象都返回true
。
如果你是OS X 10.6 / iOS 4.0或更高版本,你可能比NSPredicate更好。 请参阅-[NSArray indexesOfObjectsPassingTest:]
或编写自己的类别以添加方便的 – -select:
或-filter:
方法( 示例 )。
要其他人写这个类别,testing等等? 检查BlocksKit ( arrays文档 )。 还有更多的例子可以通过search例如“nsarray block category select”来find 。
基于Clay Bridges的回答,下面是一个使用块进行过滤的例子(将yourArray
更改为数组variables名称,将testFunc
更改为testing函数的名称):
yourArray = [yourArray objectsAtIndexes:[yourArray indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { return [self testFunc:obj]; }]];
假设你的对象都是一个类似的types,你可以添加一个方法作为他们的基类的一个类别,调用你的标准使用的函数。 然后创build一个引用该方法的NSPredicate对象。
在某些类别中定义使用你的函数的方法
@implementation BaseClass (SomeCategory) - (BOOL)myMethod { return someComparisonFunction(self, whatever); } @end
那么无论你在哪里过滤:
- (NSArray *)myFilteredObjects { NSPredicate *pred = [NSPredicate predicateWithFormat:@"myMethod = TRUE"]; return [myArray filteredArrayUsingPredicate:pred]; }
当然,如果你的函数只能和你的类中的属性进行比较,那么把函数的条件转换成谓词string可能会更容易一些。
NSPredicate
是NSPredicate
构造条件以过滤集合( 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)select * from tbl – > collection
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]];
我希望这有帮助
NSArray的+的Xh
@interface NSArray (X) /** * @return new NSArray with objects, that passing test block */ - (NSArray *)filteredArrayPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate; @end
NSArray的+ XM
@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; }];