NSPredicate 的一些用法

对数组进行过滤

// 返回值是原数组
[mutableArray filterUsingPredicate:/*NSPredicate*/];
// 返回新的数组
[mutableArray filteredArrayUsingPredicate:/*NSPredicate*/];

初始化

虽然 predicate 可以从 NSExpressionNSCompoundPredicateNSComparsionPredicate 中实例化,但它还可以用一个字符串的语法生成。这和可视化格式语言类似,我们可以用它定义排版约束。

//  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];
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容