遍历可变数组的同时删除数组元素的几种解决方案

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

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

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

        for (AddressPerson *perName in array) {
            if ([[perName name] isEqualToString:@"Zhangsan"]) {
                [array removeObject:perName];
            }
        }

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

遍历可变数组的同时删除数组元素的几种解决方案_第1张图片

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

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

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

for (int i = 0; i < [array count]; i++) {
            AddressPerson *perName = [array objectAtIndex:i];
            if ([[perName name] isEqualToString:@"Zhangsan"]) {
                [array removeObject:perName];
                NSLog(@"删除成功");
            }
        }

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

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

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

        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];
            }
        }

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

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

        // 逆序遍历,然后查找删除
        NSEnumerator *enumerator = [array reverseObjectEnumerator];
        //forin遍历
        for (AddressPerson *groupName in enumerator) {
            if ([[groupName group] isEqualToString:@"Zhangsan"]) {
                [array removeObject:groupName];
            }
        }

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

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

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

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

你可能感兴趣的:(编程语言,Objective-C)