开发中经常会遇到从数组中进行筛选数据的情况. 筛选数据本身并不困难, 但是这里要讲的是如何使用更加简单的方法来进行筛选.
正文
假设情景
假设我们有一批用户数据, 包含 姓名
, 年龄
, 身高
, 体重
信息.
首先创建一个 Person
类, 代码如下.
1
2
3
4
5
6
7
8
9
10
11
12
13
@interface Person : NSObject
@property (nonatomic, copy) NSString *name; // 姓名
@property (nonatomic, assign) NSInteger age; // 年龄
@property (nonatomic, assign) CGFloat height; // 身高
@property (nonatomic, assign) CGFloat weight; // 体重
+ (instancetype)persionWithName:(NSString *)name
age:(NSInteger)age
height:(CGFloat)height
weight:(CGFloat)weight;
@end
数据对象数组
用户信息数据对象数组如下:
1
2
3
4
5
6
7
8
9
NSArray *persons =
@[[Person persionWithName:@"张三" age:16 height:178 weight:69],
[Person persionWithName:@"李四" age:28 height:173 weight:66],
[Person persionWithName:@"王五" age:21 height:159 weight:51],
[Person persionWithName:@"赵六" age:18 height:165 weight:56],
[Person persionWithName:@"孙七" age:21 height:185 weight:73],
[Person persionWithName:@"张八" age:35 height:173 weight:61],
[Person persionWithName:@"张九" age:19 height:165 weight:52],
];
需求
假设需求(1):
从用户数据中筛选出姓
张
并且身高 > 170cm
的人.
一般最简单的做法遍历筛选
1
2
3
4
5
6
7
8
NSMutableArray *result = [NSMutableArray new];
for (Person *p in persons) {
// 1. 姓名以 `张` 为首
// 2. 身高 > 170 cm.
if ([p.name hasPrefix:@"张"] && p.height > 170) {
[result addObject:p];
}
}
这样 循环遍历数组
的做法也能完成我们的需求, 却不是本文主张的做法.
NSPredicate (谓词)
NSPredicate
(谓词) 是一个用于定义逻辑条件
的类, 主要用于 检索
或 筛选
. 对于每个做 iOS 开发的人来讲都不陌生, 但是他的强大功能却经常会被忽略掉.
同样的, 依旧
从用户数据中筛选出姓
张
并且身高 > 170cm
的人.NSPredicate
从语法上来看, 跟SQL
比较像. 如果从数据库筛选, 我们的SQL
可能会这样写:
1
SELECT * FROM `Users` WHERE `name` like 张% AND `height` > 170;
NSPredicate
会这样写:
1
name like '张*' AND height > 180
如果在本题中, 代码是这样的:
1
2
3
4
5
6
NSPredicate *predicate =
// 定义逻辑
// 1. name 以 `张` 为首
// 2. height > 170
[NSPredicate predicateWithFormat:@"name like '张*' AND height > 180"];
NSArray *result = [persons filteredArrayUsingPredicate:predicate];
此处
*
为通配符, 意为以 ‘张’ 为首, 结尾为0
或多个
字符. 无论张三
还是张三丰
都能被匹配成功.
筛选结果:
1
2
3
4
(
"张三: 16岁 178cm 69kg",
"张八: 35岁 173cm 61kg"
)
当然, 除了上面的筛选条件, 还有更多的玩法:
- 筛选出年龄介于
20
和30
之间的用户:1
[NSPredicate predicateWithFormat:@"age > 20 AND age < 30"];
- 筛选出姓
王
的用户:1 2 3 4
// 可以使用 'like' [NSPredicate predicateWithFormat:@"name like '王*'"]; // 也可以使用 'BEGINSWITH' [NSPredicate predicateWithFormat:@"name BEGINSWITH '王'"];
- 筛选出姓名中包含
三
的用户:1
[NSPredicate predicateWithFormat:@"name like '*三*'"];
此处,
三
表示三
前后都可以有>=0
字符. 比如:三
,三毛
,张三
,张三丰
,张三打太极拳
,祖师张三丰
都能够成功匹配.还有一种写法:
三
表示三
之前有1
个字符, 后面有>=0
个字符. 比如:张三
,张三丰
,张三打太极拳
, 但是无法匹配祖师张三丰
.