NSMutableArray 删除元素
2015-06-12 15:53
369 查看
在学习Objective-C的过程中,我们会学到NSMutableArray这个类,也就是可变数组。在做和可变数组相关的编程题的时候,我们会遇到一个这样的问题:在对数组遍历时删除数组元素。
有些人一看,很简单嘛,forin 遍历就解决了,我们来看一下用forin解决这个问题的结果
我们先假设一个场景,一个数组中存了n个联系人,现在我们要根据姓名删除联系人
[objc] view
plaincopyprint?
for (AddressPerson *perName in array) {
if ([[perName name] isEqualToString:@"Zhangsan"]) {
[array removeObject:perName];
}
}
这是用forin遍历来解决这个问题的代码实现,当我们运行程序时,程序crash了,这是为什么啊?逻辑是哪个没有错误啊,语法也没有报错啊?我们来看一下程序crash的原因
![](http://img.blog.csdn.net/20140809092602037?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvWmhhbmd6aGFuX3pn/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
红色框中是crash原因,意思是当数组被枚举时被修改了,因为forin遍历时规定不能修改数组元素。但是,这里有一个特殊点,假如你想要删除的是数组中最后一个元素的话,程序就不会crash了。这是因为当到最后一个元素时,已经遍历结束了,forin的工作算是结束了,你再删除数组元素已经和它没有关系了,就不会发生冲突了。
那我们应该怎么解决这个问题呢?下面我们来看几种解决方案
方案一:既然forin遍历会crash,那么我们就采用for循环遍历,我们来看一下代码:
[objc] view
plaincopyprint?
for (int i = 0; i < [array count]; i++) {
AddressPerson *perName = [array objectAtIndex:i];
if ([[perName name] isEqualToString:@"Zhangsan"]) {
[array removeObject:perName];
NSLog(@"删除成功");
}
}
这种算法是遍历整个数组,找到元素的姓名和想要删除的联系人匹配的数组元素,然后删除,用for循环遍历时可以对数组进行修改,所以这种方法是可行的.
有些人说就想用forin遍历怎么办?那么我们来看其他解决方案
方案二: 定义一个副本,遍历副本找到想要删除的元素,然后在原数组中删除对应的元素.代码实现如下:
[objc] view
plaincopyprint?
NSMutableArray *copyArray = [NSMutableArray arrayWithArray:array];
char name[20] = {0}; // 存储姓名
NSLog(@"请输入想要删除的联系人的姓名:");
scanf("%s", name);
NSString *str1 = [NSString stringWithUTF8String:name];
for (AddressPerson *perName in copyArray) {
if ([[perName name] isEqualToString:str1]) {
[array removeObject:perName];
}
}
这种算法的思想就是.对副本数组遍历,对原数组进行相应操作.
方案三:对数组逆序遍历,查找对应元素后删除
[objc] view
plaincopyprint?
// 逆序遍历,然后查找删除
NSEnumerator *enumerator = [array reverseObjectEnumerator];
//forin遍历
for (AddressPerson *groupName in enumerator) {
if ([[groupName group] isEqualToString:@"Zhangsan"]) {
[array removeObject:groupName];
}
}
这种算法的思想是:我们从数组元素最后一个开始查找,如果找到匹配的,就删除
有些人会有疑问,你这也是遍历数组时对数组进行改变不了啊,为什么逆序就可以啊?
具体情况是这样的,当我们正序遍历时,如果删除了一个,那么没有遍历到的元素位置都会往前移动一位,这样系统就无法确定接下来遍历是从删除位置开始呢,还是从删除位置下一位开始呢?这样就造成程序crash了.对于逆序遍历就不会,因为我们逆序遍历时,遇到匹配的元素删除后,位置改变的是遍历过得元素,而没有遍历到的元素位置却没有改变,所以遍历能够正常进行.
关于这个问题的解决方案暂时就这么多,如果大家觉得我写的哪种解决方案有问题,还望多多指教.如果你有更好的解决方案,希望我们能多多交流.
有些人一看,很简单嘛,forin 遍历就解决了,我们来看一下用forin解决这个问题的结果
我们先假设一个场景,一个数组中存了n个联系人,现在我们要根据姓名删除联系人
[objc] view
plaincopyprint?
for (AddressPerson *perName in array) {
if ([[perName name] isEqualToString:@"Zhangsan"]) {
[array removeObject:perName];
}
}
这是用forin遍历来解决这个问题的代码实现,当我们运行程序时,程序crash了,这是为什么啊?逻辑是哪个没有错误啊,语法也没有报错啊?我们来看一下程序crash的原因
红色框中是crash原因,意思是当数组被枚举时被修改了,因为forin遍历时规定不能修改数组元素。但是,这里有一个特殊点,假如你想要删除的是数组中最后一个元素的话,程序就不会crash了。这是因为当到最后一个元素时,已经遍历结束了,forin的工作算是结束了,你再删除数组元素已经和它没有关系了,就不会发生冲突了。
那我们应该怎么解决这个问题呢?下面我们来看几种解决方案
方案一:既然forin遍历会crash,那么我们就采用for循环遍历,我们来看一下代码:
[objc] view
plaincopyprint?
for (int i = 0; i < [array count]; i++) {
AddressPerson *perName = [array objectAtIndex:i];
if ([[perName name] isEqualToString:@"Zhangsan"]) {
[array removeObject:perName];
NSLog(@"删除成功");
}
}
这种算法是遍历整个数组,找到元素的姓名和想要删除的联系人匹配的数组元素,然后删除,用for循环遍历时可以对数组进行修改,所以这种方法是可行的.
有些人说就想用forin遍历怎么办?那么我们来看其他解决方案
方案二: 定义一个副本,遍历副本找到想要删除的元素,然后在原数组中删除对应的元素.代码实现如下:
[objc] view
plaincopyprint?
NSMutableArray *copyArray = [NSMutableArray arrayWithArray:array];
char name[20] = {0}; // 存储姓名
NSLog(@"请输入想要删除的联系人的姓名:");
scanf("%s", name);
NSString *str1 = [NSString stringWithUTF8String:name];
for (AddressPerson *perName in copyArray) {
if ([[perName name] isEqualToString:str1]) {
[array removeObject:perName];
}
}
这种算法的思想就是.对副本数组遍历,对原数组进行相应操作.
方案三:对数组逆序遍历,查找对应元素后删除
[objc] view
plaincopyprint?
// 逆序遍历,然后查找删除
NSEnumerator *enumerator = [array reverseObjectEnumerator];
//forin遍历
for (AddressPerson *groupName in enumerator) {
if ([[groupName group] isEqualToString:@"Zhangsan"]) {
[array removeObject:groupName];
}
}
这种算法的思想是:我们从数组元素最后一个开始查找,如果找到匹配的,就删除
有些人会有疑问,你这也是遍历数组时对数组进行改变不了啊,为什么逆序就可以啊?
具体情况是这样的,当我们正序遍历时,如果删除了一个,那么没有遍历到的元素位置都会往前移动一位,这样系统就无法确定接下来遍历是从删除位置开始呢,还是从删除位置下一位开始呢?这样就造成程序crash了.对于逆序遍历就不会,因为我们逆序遍历时,遇到匹配的元素删除后,位置改变的是遍历过得元素,而没有遍历到的元素位置却没有改变,所以遍历能够正常进行.
关于这个问题的解决方案暂时就这么多,如果大家觉得我写的哪种解决方案有问题,还望多多指教.如果你有更好的解决方案,希望我们能多多交流.
相关文章推荐
- 浅谈JAVA反射机制在Android应用开发中的应用
- 关于spring的介绍
- udp tcp
- WebEssentials 在vs2013 update5安装报错的解决方法.
- ASP.NET验证控件
- linux命令6--cp命令
- Docker Nova Driver实践
- Android设计模式(十二)--抽象工厂模式
- ASP.NET Session
- 第六章:架构篇 Replica Sets复制集的搭建
- C#判断字符串是否只有数字和字母组成(Regex.IsMatch)
- 用户管理
- 数组中出现次数超过一半的数字
- Win7系统应该如何使用打印机来扫描文件
- TPKeyboardAvoidingTableView 的问题
- OSG内存管理——智能指针
- 20大UI设计原则
- 第五章:mongodb 性能监控
- crontab
- UIAppearance的使用