Удаление элементов в массиве при перечислении массива - PullRequest
0 голосов
/ 10 июня 2019

Например:

NSMutableArray *array = [NSMutableArray arrayWithObjects:@"A", @"B", @"C", nil];
[array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    if ([obj isEqualToString:@"A"]) {
        [array removeObject:obj];
    }
}];
NSLog(@"%@", array);

Печать консоли B,C.

Однако:

NSMutableArray *array = [NSMutableArray arrayWithObjects:@"A", @"B", @"C", nil];
[array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    if ([obj isEqualToString:@"A"]) {
        [array removeObject:obj];
    } else if ([obj isEqualToString:@"B"]) {
        [array removeObject:obj];
    }
}];
NSLog(@"%@", array);

Печать консоли B,C.

Почему 'B, C' не 'C'?

Что произошло при удалении obj в массиве при перечислении?

Ответы [ 5 ]

1 голос
/ 10 июня 2019

Причина, по которой код не работает, упоминается правильно в других ответах, индексы изменены.

Если вы хотите удалить объекты при перечислении массива, вы должны перечислить всегда в обратном направлении .

После удаления элемента с индексом 1 индекс 0 остается без изменений.

NSMutableArray *array = [NSMutableArray arrayWithObjects:@"A", @"B", @"C", nil];
[array enumerateObjectsWithOptions: NSEnumerationReverse usingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    if ([obj isEqualToString:@"A"]) {
        [array removeObject:obj];
    } else if ([obj isEqualToString:@"B"]) {
        [array removeObject:obj];
    }
}];
NSLog(@"%@", array);
1 голос
/ 10 июня 2019

Перечислитель работает по объектам по порядку.Первый раз вы вводите блок obj = array[0], что означает obj = @"A".Затем array[0] удаляется.В следующий раз, когда вы введете блок obj = array[1], но array будет @[@"B", @"C"], поэтому obj = @"C".Вы никогда не итерируете @"B", поэтому его нельзя удалить.

В общем случае чередующиеся массивы во время итерации по ним чрезвычайно опасны и не рекомендуются.Существуют дополнительные способы удаления объектов из массива.

1 голос
/ 10 июня 2019

Возможный подход заключается в итерации массива и сохранении значений, которые вы хотите удалить

1 голос
/ 10 июня 2019

На первой итерации вы получите нулевое значение индекса, равное 'A'.Если условие выполнено.Затем А удаляется.Теперь индекс второй итерации равен One.Объект с индексом один - C. Поскольку вы удалили «A», то B переместится в нулевой индекс.Таким образом, во второй итерации он проверяет C, а не B. Поэтому B не удаляется.

0 голосов
/ 10 июня 2019

Изменение коллекции, которую вы повторяете, иногда трудно понять.Есть веские причины избегать этого, даже в вашем случае есть простое решение.(Но эти решения очень быстро ломаются, когда вы удаляете другие элементы массива.)

Существует несколько общих решений:

A.Перебрать копию

NSMutableArray *array = [NSMutableArray arrayWithObjects:@"A", @"B", @"C", nil];
NSArray *iterationArray = [array copy];
[iterationArray enumerateObjectsWithOptions: NSEnumerationReverse usingBlock:
^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  if ([obj isEqualToString:@"A"]) {
    [array removeObject:obj];
  } else if ([obj isEqualToString:@"B"]) {
    [array removeObject:obj];
  }
}];

B.Хранить объекты для удаления

NSMutableArray *array = [NSMutableArray arrayWithObjects:@"A", @"B", @"C", nil];
NSMutableArray *itemsToRemove = [NSMutableArray new];
[array enumerateObjectsWithOptions: NSEnumerationReverse usingBlock:
^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  if ([obj isEqualToString:@"A"]) {
    [itemsToRemove addObject:obj];
  } else if ([obj isEqualToString:@"B"]) {
    [itemsToRemove addObject:obj];
  }
}];
[array remveObjects:itemsToRemove];

Все эти способы сделать это , включая ваш путь , могут привести к неожиданным результатам, поскольку -removeObject: удаляет все вхождения объекта всам массив, что означает удаление всех объектов, которые равны аргументу, включая объекты, которые не идентичны.

C.Удаление объектов с этими индексами

Если вы выполняете итерацию с использованием индекса - или можете легко построить индекс - более эффективно сохранить индексы, а затем удалить с этим.Это дает вам возможность различаться между одинаковыми и одинаковыми объектами.В вашем случае

NSMutableArray *array = [NSMutableArray arrayWithObjects:@"A", @"B", @"C", nil];
NSMutableIndexSet *itemsToRemove = [NSMutableIndexSet new];
__block NSUInteger index=0;
[array enumerateObjectsWithOptions: NSEnumerationReverse usingBlock:
^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) 
{
  if ([obj isEqualToString:@"A"]) 
  {
    [itemsToRemove addIndex:index];
  } else if ([obj isEqualToString:@"B"]) {
    [itemsToRemove addIndex:index];
  }
  index++;
}];
[array removeObjectsAtIndexes:itemsToRemove];
NSLog(@"%@", array);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...