数组如何一边遍历一边删除元素

来源:互联网 发布:大数据与云计算知乎 编辑:程序博客网 时间:2024/04/28 10:14

1.此文转载于http://blog.csdn.net/zhangzhan_zg/article/details/38453305

在学习Objective-C的过程中,我们会学到NSMutableArray这个类,也就是可变数组。在做和可变数组相关的编程题的时候,我们会遇到一个这样的问题:在对数组遍历时删除数组元素。

有些人一看,很简单嘛,forin 遍历就解决了,我们来看一下用forin解决这个问题的结果

我们先假设一个场景,一个数组中存了n个联系人,现在我们要根据姓名删除联系人

[objc] view plain copy
 print?
  1. <span style="font-size:18px;">        for (AddressPerson *perName in array) {  
  2.             if ([[perName name] isEqualToString:@"Zhangsan"]) {  
  3.                 [array removeObject:perName];  
  4.             }  
  5.         }</span>  

这是用forin遍历来解决这个问题的代码实现,当我们运行程序时,程序crash了,这是为什么啊?逻辑是哪个没有错误啊,语法也没有报错啊?我们来看一下程序crash的原因


红色框中是crash原因,意思是当数组被枚举时被修改了,因为forin遍历时规定不能修改数组元素。但是,这里有一个特殊点,假如你想要删除的是数组中最后一个元素的话,程序就不会crash了。这是因为当到最后一个元素时,已经遍历结束了,forin的工作算是结束了,你再删除数组元素已经和它没有关系了,就不会发生冲突了。

那我们应该怎么解决这个问题呢?下面我们来看几种解决方案

方案一:既然forin遍历会crash,那么我们就采用for循环遍历,我们来看一下代码:

[objc] view plain copy
 print?
  1. for (int i = 0; i < [array count]; i++) {  
  2.             AddressPerson *perName = [array objectAtIndex:i];  
  3.             if ([[perName name] isEqualToString:@"Zhangsan"]) {  
  4.                 [array removeObject:perName];  
  5.                 NSLog(@"删除成功");  
  6.             }  
  7.         }  

这种算法是遍历整个数组,找到元素的姓名和想要删除的联系人匹配的数组元素,然后删除,用for循环遍历时可以对数组进行修改,所以这种方法是可行的.

有些人说就想用forin遍历怎么办?那么我们来看其他解决方案

方案二: 定义一个副本,遍历副本找到想要删除的元素,然后在原数组中删除对应的元素.代码实现如下:

[objc] view plain copy
 print?
  1. NSMutableArray *copyArray = [NSMutableArray arrayWithArray:array];  
  2. char name[20] = {0}; // 存储姓名  
  3. NSLog(@"请输入想要删除的联系人的姓名:");  
  4. scanf("%s", name);  
  5. NSString *str1 = [NSString stringWithUTF8String:name];  
  6. for (AddressPerson *perName in copyArray) {  
  7.     if ([[perName name] isEqualToString:str1]) {  
  8.         [array removeObject:perName];  
  9.     }  
  10. }  

这种算法的思想就是.对副本数组遍历,对原数组进行相应操作.

方案三:对数组逆序遍历,查找对应元素后删除

[objc] view plain copy
 print?
  1. // 逆序遍历,然后查找删除  
  2. NSEnumerator *enumerator = [array reverseObjectEnumerator];  
  3. //forin遍历  
  4. for (AddressPerson *groupName in enumerator) {  
  5.     if ([[groupName group] isEqualToString:@"Zhangsan"]) {  
  6.         [array removeObject:groupName];  
  7.     }  
  8. }  

这种算法的思想是:我们从数组元素最后一个开始查找,如果找到匹配的,就删除

有些人会有疑问,你这也是遍历数组时对数组进行改变不了啊,为什么逆序就可以啊?

具体情况是这样的,当我们正序遍历时,如果删除了一个,那么没有遍历到的元素位置都会往前移动一位,这样系统就无法确定接下来遍历是从删除位置开始呢,还是从删除位置下一位开始呢?这样就造成程序crash了.对于逆序遍历就不会,因为我们逆序遍历时,遇到匹配的元素删除后,位置改变的是遍历过得元素,而没有遍历到的元素位置却没有改变,所以遍历能够正常进行.

关于这个问题的解决方案暂时就这么多,如果大家觉得我写的哪种解决方案有问题,还望多多指教.如果你有更好的解决方案,希望我们能多多交流.


0 0
原创粉丝点击