iOS - NSPredicate 使用详解


NSPredicate 简述

NSPredicate类是一种过滤器,用来定义 逻辑条件约束的获取 或 内存中的。

在别写 NSPredicate 语句的时候,可以使用

  • 比较运算符: 大于等于 >=,=>, 小于等于<=,=<,不等于!=、<>, 相等 =;
  • 逻辑运算符(与或非)AND、&&;OR、||;NOT、 !;
  • 字符串比较运算符:BEGINSWITH、ENDSWITH、CONTAINS、LIKE
  • 集合运算符:ANY、SOME、ALL、NONE、IN
  • 直接量:FALSE、NO;TRUE、YES;NULL、NIL;SELF、"string"或’string’;数组,如:{‘one’, ‘two’, ‘three’}(和c中的写法相同);数值、十六进制数:0x开;八进制:0o开头;二进制:0b开头的数字。
  • 保留字:AND、OR、IN、NOT、ALL、ANY、SOME、NONE、LIKE、CASEINSENSITIVE、CI、MATCHES、CONTAINS、BEGINSWITH、ENDSWITH、BETWEEN、NULL、NIL、SELF、TRUE、YES、FALSE、NO、FIRST、LAST、SIZE、ANYKEY、SUBQUERY、CAST、TRUEPREDICATE、FALSEPREDICATE

使用示例

一、过滤数值

是否复合某个条件,返回BOOL,使用方法如:
下面例子,都是用下面数值做测试:

    NSNumber *num0 = @123;
    NSNumber *num1 = @1234;
    NSString *str0 = @"123";

1、判断数值相等、大小等

  • =、:判断两个表达式是否相等,在谓词中=和是相同的意思都是判断,而没有赋值这一说;
  • 字符串不能使用 = 判断;
    NSNumber *num0 = @123;
    NSNumber *num1 = @1234;
    NSString *str0 = @"123";
    
    NSPredicate *pre0 = [NSPredicate predicateWithFormat:@"SELF = 123"];
    NSLog(@"%d",[pre0 evaluateWithObject:num0]);//1
    NSLog(@"%d",[pre0 evaluateWithObject:num1]);//0
    NSLog(@"%d",[pre0 evaluateWithObject:str0]);//0
    
    NSPredicate *pre1 = [NSPredicate predicateWithFormat:@"SELF > 1000"];
    NSLog(@"%d",[pre1 evaluateWithObject:num0]);//1
    NSLog(@"%d",[pre1 evaluateWithObject:num1]);//0
    

2、判断数值范围 Between

  • 表达式 BETWEEN {下限,上限}的格式,要求该表达式必须大于或等于下限,并小于或等于上限
    NSPredicate *pre2 = [NSPredicate predicateWithFormat:@"SELF BETWEEN {100, 200}"];
    NSLog(@"%d",[pre2 evaluateWithObject:num0]);//1
    NSLog(@"%d",[pre2 evaluateWithObject:num1]);//0
    

二、过滤字符串

1、BEGINSWITH:是否以指定字符串开头

如:判断字符串是否以a开头:BEGINSWITH ‘a’)

    NSPredicate *pre = [NSPredicate predicateWithFormat:@"SELF BEGINSWITH 'a'"];
    
    NSLog(@"%d",[pre evaluateWithObject:@"ab"]);//1
    NSLog(@"%d",[pre evaluateWithObject:@"abc"]);//1
    NSLog(@"%d",[pre evaluateWithObject:@"ba"]);//0

2、ENDSWITH:是否以指定字符串结尾

如:判断字符串是否以ba结尾:ENDSWITH ‘ba’)

    NSPredicate *pre = [NSPredicate predicateWithFormat:@"SELF ENDSWITH 'ba'"];
    
    NSLog(@"%d",[pre evaluateWithObject:@"ab"]);//0
    NSLog(@"%d",[pre evaluateWithObject:@"abc"]);//0
    NSLog(@"%d",[pre evaluateWithObject:@"ba"]);//1
    NSLog(@"%d",[pre evaluateWithObject:@"cba"]);//1

3、CONTAINS:是否包含指定字符串

    NSPredicate *pre = [NSPredicate predicateWithFormat:@"SELF CONTAINS 'jo'"];
    
    NSLog(@"%d",[pre evaluateWithObject:@"John"]);//0
    NSLog(@"%d",[pre evaluateWithObject:@"john"]);//1
    NSLog(@"%d",[pre evaluateWithObject:@"Milly"]);//0

4、LIKE & ?:是否匹配指定字符串模板

其之后可以跟?代表一个字符和*代表任意多个字符两个通配符。

4.1 ? 代表一个字符

   NSPredicate *pre = [NSPredicate predicateWithFormat:@"SELF LIKE '?ng'"];
    NSLog(@"%d",[pre evaluateWithObject:@"png"]);//1
    NSLog(@"%d",[pre evaluateWithObject:@"jpng"]);//0

4.2* 代表任意多个字符

样式类似 前缀为 ang,后面跟随其他字符:

NSPredicate *pre = [NSPredicate predicateWithFormat:@"SELF LIKE 'ang*'"];
    
    NSLog(@"%d",[pre evaluateWithObject:@"ango"]);//1
    NSLog(@"%d",[pre evaluateWithObject:@"angel"]);//1
    NSLog(@"%d",[pre evaluateWithObject:@"jiang"]);//0

上面条件,angle和lenang都符合;
你也可以把 * 放到 ang 前面。


5、MATCHES:是否匹配指定的正则表达式

虽然正则表达式的执行效率是最低的,但其功能是最强大的,也是我们最常用的。

- (void)checkPhoneNumber
{
    NSString *regex = @"^[1][3-8]\\d{9}$";
    NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
    NSLog(@"%d", [pred evaluateWithObject:@"15818663297"]);//1
    NSLog(@"%d", [pred evaluateWithObject:@"303178203"]);//0
}

6、字符串比较都是区分大小写和重音符号的。

如:café和cafe是不一样的,Cafe和cafe也是不一样的。判断时可以加上下面符号进行区分:

[c] 忽略大小写;
[d] 忽略重音符号;比如:name LIKE[cd] ‘cafe’,那么不论name是cafe、Cafe还是café上面的表达式都会返回YES。
[cd]既不区分大小写,也不区分发音符号。

NSArray *stringArray = @[@"John",@"john",@"Jolly",@"Milly"];
    NSString *targetString = @"jo";
    NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF CONTAINS[cd] %@",targetString];
    NSLog(@"%@",[stringArray filteredArrayUsingPredicate:pred]);// John,john,Jolly

7、IN 运算

对于 NSString类型,判断title属性是否是字符串@"angle"和@"addss"中的一个:

    NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF IN {'angle', 'addss'}"];
    NSLog(@"%d", [pred evaluateWithObject:@"angle"]);//1
    NSLog(@"%d", [pred evaluateWithObject:@"blue"]);//0

对于 NSNumber类型,判断testID属性是否是NSNumber对象中的@1和@13中的一个:

    NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF IN {1, 13}"];
    
    NSLog(@"%d", [pred evaluateWithObject:@(13)]);//1
    NSLog(@"%d", [pred evaluateWithObject:@(5)]);//0

AND(或&&)

NSPredicate *pred = [NSPredicate predicateWithFormat:@“testID >= %@ AND testID <=%@”, @1ll, @13ll];


三、过滤数组、Set

0、过滤方法

过滤 NSArray:filteredArrayUsingPredicate:

使用指定的谓词过滤NSArray集合,返回符合条件的元素组成的 新集合

NSMutableArray:filterUsingPredicate:

使用指定的谓词过滤NSMutableArray,剔除集合中不符合条件的元素

NSSet filteredSetUsingPredicate:

NSMutableSet filterUsingPredicate:

通过上面的描述可以看出,使用谓词过滤不可变集合和可变集合的区别是:过滤不可变集合时,会返回符合条件的集合元素组成的新集合;过滤可变集合时,没有返回值,会直接剔除不符合条件的集合元素


1、数值数组筛选

数值数组,筛选数值在某个范围内

    NSArray *testArray = @[@1, @2, @3, @4, @5, @6];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF > 2 && SELF < 5"];
    NSArray *filterArray = [testArray filteredArrayUsingPredicate:predicate];
    NSLog(@"filterArray:%@", filterArray);//3,4

2、字符串数组的筛选

常用的一般根据包含内容、字符串长度进行筛选
其他功能可参考上面对字符串进行判断的方法

- (void)testPre1{
    NSArray *testArray = @[@"JOLLY",@"billy", @"John", @"Joe", @"Tiffany", @"Mary", @"David"];
    //筛选字符长度大于4的元素
    NSPredicate *pre0 = [NSPredicate predicateWithFormat:@"SELF.length > 4"];
    NSArray *filterArray0 = [testArray filteredArrayUsingPredicate:pre0];
    
    NSLog(@"filterArray0:%@", filterArray0);//billy,Tiffany,David
    
    //取出包含‘Jo’的元素
    NSPredicate *pre1 = [NSPredicate predicateWithFormat:@"SELF CONTAINS 'Jo'"];
    NSArray *filterArray1 = [testArray filteredArrayUsingPredicate:pre1];
    NSLog(@"filterArray1:%@", filterArray1);//John,Joe
    
    NSString *keyword = @"Jo";
    NSPredicate *pre2 = [NSPredicate predicateWithFormat:@"SELF.lowercaseString CONTAINS '%@'",keyword.lowercaseString];
    
    NSArray *filterArray2 = [testArray filteredArrayUsingPredicate:pre2];
    NSLog(@"filterArray2:%@", filterArray2);//JOLLY,John,Joe
}

3、取两个数组的交集

使用 集合运算符中的 IN 运算符

    NSArray *array = @[@"a", @"ab", @"abc", @"abcd"];
    NSArray *subArray = @[@"ab", @"abc",@"ab1"];
    
    NSPredicate *pre0 = [NSPredicate predicateWithFormat:@"NOT (SELF IN %@)", subArray];//不包含在subArray的元素
    NSLog(@"0-%@", [array filteredArrayUsingPredicate:pre0]);//a,abcd
    
    
    NSPredicate *pre1 = [NSPredicate predicateWithFormat:@"SELF IN %@", subArray];//包含在subArray的元素
    NSLog(@"1-%@", [array filteredArrayUsingPredicate:pre1]);//ab,abc

4、过滤模型数组

这里创建一个模型 PersonModel 方便解释下面使用,PersonModel 包含属性:

@property (nonatomic,copy) NSString *name;
@property (nonatomic,copy) NSString *sex;
@property (nonatomic,assign) NSInteger age;
-(instancetype)initWithName:(NSString *)name sex:(NSString *)sex age:(NSInteger)age;

创建测试数据:


    PersonModel *model0 = [[PersonModel alloc]initWithName:@"joe" sex:@"female" age:18];
    PersonModel *model1 = [[PersonModel alloc]initWithName:@"jim" sex:@"female" age:20];
    PersonModel *model2 = [[PersonModel alloc]initWithName:@"jone" sex:@"female" age:23];
    PersonModel *model3 = [[PersonModel alloc]initWithName:@"milly" sex:@"female" age:25];
    PersonModel *model4 = [[PersonModel alloc]initWithName:@"Elaine" sex:@"female" age:28];
    
    NSArray *array = @[model0,model1,model2,model3,model4];

筛选名字包含 jo 的模型, 下面四种方式搜索结果相同:

    NSPredicate *pred0 = [NSPredicate predicateWithFormat:@"%K CONTAINS %@", @"name", @"jo"];
    NSPredicate *pred1 = [NSPredicate predicateWithFormat:@"name CONTAINS %@", @"jo"];
    NSPredicate *pred2 = [NSPredicate predicateWithFormat:@"SELF.name CONTAINS %@", @"jo"];
    NSPredicate *predTemp3 = [NSPredicate predicateWithFormat:@"%K CONTAINS $VALUE", @"name"];
    NSPredicate* pred3 = [predTemp3 predicateWithSubstitutionVariables:@{@"VALUE" : @"jo"}];
    
    NSLog(@"%@", [array filteredArrayUsingPredicate:pred0]);
    NSLog(@"%@", [array filteredArrayUsingPredicate:pred1]);
    NSLog(@"%@", [array filteredArrayUsingPredicate:pred2]);
    NSLog(@"%@", [array filteredArrayUsingPredicate:pred3]);

其中

  • 属性作为key,可以用 %K 表示。
  • 使用 $ 修饰的字符,可以作为参数,在 predicateWithSubstitutionVariables 中使用字典的形式赋值;在其他时候赋值,也方便产生多个条件类似的过滤器。Value 字符也可以替换为其他字符,只要前后统一即可,最好不要用关键字。
    下面示例同样使用到这个方法,方便你的理解:

predicateWithSubstitutionVariables

    // 创建谓词,属性名改为age,要求这个age包含$VALUE字符串
    NSPredicate *predTemp4 = [NSPredicate predicateWithFormat:@"%K > $VALUE", @"age"];
    // 指定$VALUE的值为 20
    NSPredicate *pred4 = [predTemp4 predicateWithSubstitutionVariables:@{@"VALUE" : @20}];
    NSLog(@"%@", [array filteredArrayUsingPredicate:pred4]);//筛选到年级大于20的模型

参考资料

  • suiling:iOS中的谓词(NSPredicate)使用
    http://www.cocoachina.com/ios/20160111/14926.html

  • Lonely:NSPredicate用法
    http://www.jianshu.com/p/f5bcefff91b5

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是一个使用NSPredicate的Swift代码示例,用于将大量数据按时间分组: ```swift struct DataItem { let name: String let timeStamp: TimeInterval // 时间戳 } func groupDataByTime(_ data: [DataItem]) -> [[DataItem]] { // 将数据按时间先后排序 let sortedData = data.sorted { $0.timeStamp < $1.timeStamp } // 创建空字典 var groups = [String: [DataItem]]() // 使用NSPredicate过滤并分组数据 let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd" for item in sortedData { let date = Date(timeIntervalSince1970: item.timeStamp) let dateString = dateFormatter.string(from: date) let predicate = NSPredicate(format: "SELF.dateString == %@", dateString) let filteredArray = (groups as NSDictionary).filtered(using: predicate) if var items = filteredArray.first?.value as? [DataItem] { items.append(item) groups[dateString] = items } else { groups[dateString] = [item] } } // 将分组后的数据按时间先后顺序排序 let sortedGroups = groups.sorted { $0.key < $1.key } // 将所有分组添加到一个数组中 var result = [[DataItem]]() for (_, items) in sortedGroups { result.append(items) } return result } ``` 在这个示例中,我们同样定义了一个`DataItem`结构体来表示数据的名称和时间戳。`groupDataByTime`函数首先将数据按时间先后排序,然后使用`NSPredicate`过滤并分组数据。我们指定`NSPredicate`的格式为`SELF.dateString == %@`,其中`dateString`是我们根据时间戳计算得到的时间字符串,`%@`是用于替换的占位符。通过对字典进行过滤,我们可以得到一个包含指定时间字符串的数组,然后将新的数据项添加到这个数组中。最后,我们将所有分组添加到一个大数组中,按时间先后顺序排序,并返回结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI工程化

请我喝杯伯爵奶茶~!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值