我有一个NSArray
,我想NSArray
用原始数组中满足特定条件的对象创建一个新对象。条件由返回 a 的函数决定BOOL
。
我可以创建一个NSMutableArray
, 遍历源数组并复制过滤器函数接受的对象,然后创建它的不可变版本。
有没有更好的办法?
我有一个NSArray
,我想NSArray
用原始数组中满足特定条件的对象创建一个新对象。条件由返回 a 的函数决定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.
}]];
我认为这是尽可能简洁。
对于那些NSArray
在 Swift 中使用 s 的人,你可能更喜欢这个更简洁的版本:
let filteredArray = array.filter { $0.shouldIKeepYou() }
filter
只是一个方法Array
(NSArray
隐式桥接到 Swift 的Array
)。它接受一个参数:一个闭包,它接受数组中的一个对象并返回一个Bool
. 在您的闭包中,只需true
在过滤后的数组中返回您想要的任何对象。
根据 Clay Bridges 的回答,这是一个使用块进行过滤的示例(更改yourArray
为您的数组变量名称和testFunc
测试函数的名称):
yourArray = [yourArray objectsAtIndexes:[yourArray indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
return [self testFunc:obj];
}]];
如果您是 OS X 10.6/iOS 4.0 或更高版本,那么使用块可能比使用 NSPredicate 更好。查看-[NSArray indexesOfObjectsPassingTest:]
或编写您自己的类别以添加方便-select:
或-filter:
方法(示例)。
希望其他人编写该类别,对其进行测试等?查看BlocksKit(数组文档)。还有更多的例子可以通过搜索来找到,例如“nsarray block category select”。
假设您的对象都是相似的类型,您可以添加一个方法作为其基类的一个类别,该类别调用您用于标准的函数。然后创建一个引用该方法的 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]];
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]];
我希望这有帮助
签出这个库
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;
}
您可以使用的另一种分类方法:
- (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];
}