Подтвердить что ты не робот

Удаление из массива во время перечисления в Swift?

Я хочу перечислить массив в Swift и удалить определенные элементы. Мне интересно, безопасно ли это делать, а если нет, то как я должен это достичь.

В настоящее время я буду делать это:

for (index, aString: String) in enumerate(array) {
    //Some of the strings...
    array.removeAtIndex(index)
}
4b9b3361

Ответ 1

В Swift 2 это довольно просто, используя enumerate и reverse.

var a = [1,2,3,4,5,6]
for (i,num) in a.enumerate().reverse() {
    a.removeAtIndex(i)
}
print(a)

Смотрите мой swiftstub здесь: http://swiftstub.com/944024718/?v=beta

Ответ 2

Вы можете рассмотреть способ filter:

var theStrings = ["foo", "bar", "zxy"]

// Filter only strings that begins with "b"
theStrings = theStrings.filter { $0.hasPrefix("b") }

Параметр filter - это просто замыкание, которое принимает экземпляр типа массива (в данном случае String) и возвращает a Bool. Когда результат true, он сохраняет элемент, иначе элемент отфильтровывается.

Ответ 3

В Swift 3 и 4 это будет:

С цифрами, в соответствии с ответом Джонстона:

var a = [1,2,3,4,5,6]
for (i,num) in a.enumerated().reversed() {
   a.remove(at: i)
}
print(a)

Со строками strings в качестве OP-вопроса:

var b = ["a", "b", "c", "d", "e", "f"]

for (i,str) in b.enumerated().reversed()
{
    if str == "c"
    {
        b.remove(at: i)
    }
}
print(b)

Однако теперь в Swift 4.2 и более поздних версиях есть даже лучший, более быстрый способ, который был рекомендован Apple в WWDC2018:

var c = ["a", "b", "c", "d", "e", "f"]
c.removeAll(where: {$0 == "c"})
print(c)

У этого нового способа есть несколько преимуществ:

  1. Это быстрее, чем реализации с filter.
  2. Это устраняет необходимость обращения к массивам.
  3. Он удаляет элементы на месте и, таким образом, обновляет исходный массив, а не размещает и возвращает новый массив.

Ответ 4

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

Итак, лучший способ - перемещаться по массиву в обратном порядке - и в этом случае я предлагаю использовать традиционный цикл for:

for var index = array.count - 1; index >= 0; --index {
    if condition {
        array.removeAtIndex(index)
    }
}

Однако, на мой взгляд, лучший подход заключается в использовании метода filter, как описано в его ответе @perlfly.

Ответ 5

Нет, это небезопасно, чтобы мутировать массивы во время перезаписи, ваш код сработает.

Если вы хотите удалить только несколько объектов, вы можете использовать функцию filter.

Ответ 6

Либо создайте изменчивый массив для хранения элементов, которые нужно удалить, а затем, после перечисления, удалите эти элементы из оригинала. Или создайте копию массива (неизменяемый), перечислите это и удалите объекты (не по индексу) из оригинала при перечислении.

Ответ 7

Я рекомендую установить элементы в nil во время перечисления и после завершения удалить все пустые элементы с помощью метода array() array().

Ответ 8

Традиционный цикл for можно заменить простым циклом while, который полезен, если вам также необходимо выполнить некоторые другие операции с каждым элементом перед удалением.

var index = array.count-1
while index >= 0 {

     let element = array[index]
     //any operations on element
     array.remove(at: index)

     index -= 1
}