对数组进行过滤
// 返回值是原数组
[mutableArray filterUsingPredicate:/*NSPredicate*/];
// 返回新的数组
[mutableArray filteredArrayUsingPredicate:/*NSPredicate*/];
初始化
虽然 predicate 可以从 NSExpression、NSCompoundPredicate 或 NSComparsionPredicate 中实例化,但它还可以用一个字符串的语法生成。这和可视化格式语言类似,我们可以用它定义排版约束。
// USERIDS 是一个包含 userId 的集合
// 查询 employees <People集合> 中的 identifier 在 USERIDS的
NSPredicate *morningAttendees = [NSPredicate predicateWithFormat:@"SELF.identifier IN %@", USERIDS];
NSArray *peopleAttendingMorningEvent = [employees filteredArrayUsingPredicate:morningAttendees];
NSPredicate 引入了 keypath来做匹配
[NSPredicate predicateWithFormat:@"SELF.%K IN %@", @"identifier", peopleAttendingMorningEvent];
假设我们还需要像上面一样找到所有参加活动的人,但还要满足他们的工资水平在 50000 到 60000 之间。
[NSPredicate predicateWithFormat:@"SELF.identifier IN %@ && SELF.paygrade.integerValue BETWEEN {50000, 60000}", peopleAttendingMorningEvent];
为了提高可读性,符号和字符是都支持的
&& 或 AND
|| 或 OR
! 或 NOT
比较
CONTAINS 包含 x
BEGINSWITH 以 x 开始
ENDSWITH 以 x 结束
LIKE 模糊匹配
// 查询 self.name 是以 `K`开头的
[NSPredicate predicateWithFormat:@"SELF.name BEGINSWITH 'K'"];
// 查询是以 Kar* 来模糊匹配的
[NSPredicate predicateWithFormat:@"SELF.name LIKE 'Kar*'"];
// 复合查询
NSString *predicateFormat = @"(SELF.name LIKE 'Kar*') AND (SELF.paygrade.intValue >= 10)";
NSPredicate *namesStringWithK = [NSPredicate predicateWithFormat:predicateFormat];
同样的也支持 正则表达式
// phoneNumberRegex 手机号正则
[NSPredicate predicateWithFormat:@"SELF.phoneNumber MATCHES %@", phoneNumberRegex];
为了安全可以结合 NSStringFromSelector一起使用
NSString *predicateFormat = @"(SELF.%@ LIKE 'Kar*') AND (SELF.paygrade.intValue >= 10)"
NSString *kpName = NSStringFromSelector(@selector(identifier));
NSString *kpPaygrade = NSStringFromSelector(@selector(paygrade));
NSPredicate *namesStartingWithK = [NSPredicate predicateWithFormat:predicateFormat, kpName, kpPaygrade];
// 现在只有 Karl 了
[mutablePersonAr filterUsingPredicate:namesStartingWithK];
KeyPath 集合查询
// 假设一个 Person 对象现在有一个下面的属性:
// NSArray *previousPay
// 找到所有满足过去工资的平均值大于 10 的人
NSString *predicateFormat = @"SELF.previousPay.@avg.doubleValue > 10";
NSPredicate *previousPayOverTen = [NSPredicate predicateWithFormat:predicateFormat];
// 所有过去工资的平均值大于 10 的人
[mutablePersonAr filterUsingPredicate:previousPayOverTen];
@avg 均值
@sum 求和
@max 最大值
@min 最小值
@count 数量
数组的深入探讨
array[FIRST] array[LAST] array[SIZE] array[index]
// 找到所有过去有三份不同工资的人
NSString *predicateFormat = @"previousPay[SIZE] == 3";
NSPredicate *threePreviousSalaries = [NSPredicate predicateWithFormat:predicateFormat];
// 这些 Person 对象过去有三份不同的工资
[mutablePersonAr filterUsingPredicate:threePreviousSalaries];
// 找到所有过去有三个不同的工资以及第一份工资大于 8 的人
NSString *predicateFormat = @"(previousPay[SIZE] == 3) AND (previousPay[FIRST].intValue > 8)";
NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateFormat];
[mutablePersonAr filterUsingPredicate:predicate];
更复杂的情况
@distinctUnionOfArrays
@unionOfArrays
@unionOfObjects
@distinctUnionOfObjects
// 假设 p1/2/3/4 都是 Person 对象
NSArray <P*> *previousEmployees = @[@[p1],@[p2,p1,p2],@[p1],@[p4,p2],@[p4],@[p4],@[p1]];
// 获取所有不同的 ID
NSArray *unqiuePreviousEmployeeIDs = [previousEmployees valueForKeyPath:@"@distinctUnionOfObjects.identifier"];
// 现在数组里应该只含有不同的 ID
子查询
// 假设 Person 对象有了一个新的属性表示他们的队伍:
// NSArray *team;
// 从雇员数组中找出这样的人,他们的团队中有人满足这个条件:没有历史工资数据并且工资大于 1
NSString *predicateFormat = @"SUBQUERY(team, $teamMember, $teamMember.paygrade.intValue > 1 AND $teamMember.previousPay == nil).@count > 0";
NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateFormat];
[employeeAr filterUsingPredicate:predicate];