2015-02-04 1 views
49

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

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

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

ответ

4

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

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

+2

Это неверно для Swift. Массивы являются ** значениями ** типов, поэтому они «копируются», когда они передаются в функции, присваиваются переменным или используются в перечислении. (Swift реализует функцию копирования на запись для типов значений, поэтому фактическое копирование сведено к минимуму.) Попробуйте выполнить следующее: var x = [1, 2, 3, 4, 5]; печать (х); var i = 0; для v в x {if (v% 2 == 0) {x.remove (at: i)} else {i + = 1}}; print (x) – 404compilernotfound

+0

Да, вы правы, при условии, что вы точно знаете, что делаете. Возможно, я не смог четко выразить свой ответ. Я должен был сказать * Это возможно, но это небезопасно *. Это небезопасно, потому что вы мутируете размер контейнера, и если вы ошибаетесь в своем коде, ваше приложение выйдет из строя. Swift все о написании безопасного кода, который не будет неожиданно разбиваться во время выполнения. Вот почему использование функциональных функций программирования, таких как 'filter', является _safer_. Вот мой немой пример: 'var y = [1, 2, 3, 4, 5]; print (y); для (индекс, значение) в y.enumerated() { y.remove (at: index) } print (y) ' – Starscream

+0

Я просто хотел бы выделить, что можно изменить список, который перечисляется в Swift, так как в отличие от поведения, генерирующего исключения, при повторении через NSArray с быстрым перечислением или даже с типами коллекции C#. Это не модификация, которая могла бы вызвать здесь исключение, но возможность расходовать индексы и выйти за пределы (потому что они уменьшили размер). Но я определенно согласен с вами в том, что обычно безопаснее и яснее использовать тип функционального программирования для управления коллекциями. Особенно в Свифт. – 404compilernotfound

47

Вы могли бы рассмотреть filter путь:

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

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

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

+12

Я бы сказал, что 'filter' не обновляет массив, он просто возвращает новый – Antonio

+0

Скобки должны быть удалены; это закрывающее закрытие. – Jessy

+0

@ Антонио, ты прав. Именно поэтому я опубликовал его как более безопасное решение. Для огромных массивов можно было бы рассмотреть другое решение. –

1

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

+1

Это работает только в том случае, если сохраненный тип является необязательным. Также обратите внимание, что метод 'filter' не удаляет, он генерирует новый массив. – Antonio

+0

Согласен. Обратный порядок - лучшее решение. – freele

2

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

12

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

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

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

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

51

В 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

+0

Работает, но фильтр действительно способ пойти –

+10

@Mayerz False. «Я хочу ** перечислить ** через массив в Swift и удалить определенные элементы». 'filter' возвращает новый массив. Вы ничего не удаляете из массива. Я бы даже не назвал 'filter' перечислением. Существует всегда более чем один способ кожи кошки. – Johnston

+4

rigth, мой плохой! Pla dont skin any cats –

10

В Swift 3, это было бы:

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

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

С строк как вопрос 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) 
Смежные вопросы