Quiero enumerar a través de una matriz en Swift y eliminar ciertos elementos. Me pregunto si es seguro hacerlo y, si no, cómo se supone que debo lograrlo.
Actualmente, estaría haciendo esto:
for (index, aString: String) in enumerate(array) {
//Some of the strings...
array.removeAtIndex(index)
}
ios
arrays
swift
enumeration
Andrés
fuente
fuente
filter
devuelve una nueva matriz. No está eliminando nada de la matriz. Ni siquiera llamaríafilter
una enumeración. Siempre hay más de una forma de despellejar a un gato.Puede considerar la
filter
forma:var theStrings = ["foo", "bar", "zxy"] // Filter only strings that begins with "b" theStrings = theStrings.filter { $0.hasPrefix("b") }
El parámetro de
filter
es solo un cierre que toma una instancia de tipo de matriz (en este casoString
) y devuelve unBool
. Cuando el resultado estrue
, mantiene el elemento; de lo contrario, el elemento se filtra.fuente
filter
no actualiza la matriz, solo devuelve una nuevafilter
método enmutating
uno entonces (como he leído, lamutating
palabra clave permite que funciones como esta se modifiquenself
)?Array
marcarlo comomutating
y similar al código de la pregunta. De todos modos, considere que esto no siempre puede ser una ventaja. De todos modos, cada vez que elimina un objeto, su matriz puede reorganizarse en la memoria. Por lo tanto, podría ser más eficiente asignar una nueva matriz y luego realizar una sustitución atómica con el resultado de la función de filtro. El compilador podría hacer aún más optimizaciones, dependiendo de su código.En Swift 3 y 4 , esto sería:
Con números, según la respuesta de Johnston:
var a = [1,2,3,4,5,6] for (i,num) in a.enumerated().reversed() { a.remove(at: i) } print(a)
Con cadenas como la pregunta del 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)
Sin embargo, ahora en Swift 4.2 o posterior, hay una forma mejor y más rápida que fue recomendada por Apple en WWDC2018:
var c = ["a", "b", "c", "d", "e", "f"] c.removeAll(where: {$0 == "c"}) print(c)
Esta nueva forma tiene varias ventajas:
filter
.fuente
{$0 === Class.self}
no funciona?Cuando un elemento en un índice determinado se elimina de una matriz, todos los elementos posteriores tendrán su posición (e índice) cambiados, porque retroceden una posición.
Entonces, la mejor manera es navegar por la matriz en orden inverso, y en este caso sugiero usar un bucle for tradicional:
for var index = array.count - 1; index >= 0; --index { if condition { array.removeAtIndex(index) } }
Sin embargo, en mi opinión, el mejor enfoque es utilizar el
filter
método, como lo describe @perlfly en su respuesta.fuente
No, no es seguro mutar matrices durante la enumeración, su código se bloqueará.
Si desea eliminar solo algunos objetos, puede usar la
filter
función.fuente
filter
es más seguro . Aquí está mi un ejemplo tonto:var y = [1, 2, 3, 4, 5]; print(y); for (index, value) in y.enumerated() { y.remove(at: index) } print(y)
Cree una matriz mutable para almacenar los elementos que se eliminarán y luego, después de la enumeración, elimine esos elementos del original. O bien, cree una copia de la matriz (inmutable), enumere eso y elimine los objetos (no por índice) del original mientras enumera.
fuente
El bucle for tradicional podría reemplazarse por un bucle while simple, útil si también necesita realizar otras operaciones en cada elemento antes de eliminarlo.
var index = array.count-1 while index >= 0 { let element = array[index] //any operations on element array.remove(at: index) index -= 1 }
fuente
Recomiendo establecer los elementos en nil durante la enumeración y, después de completar, eliminar todos los elementos vacíos utilizando el método filter () de matrices.
fuente
filter
método no se elimina, genera una nueva matriz.Solo para agregar, si tiene varias matrices y cada elemento en el índice N de la matriz A está relacionado con el índice N de la matriz B, entonces aún puede usar el método invirtiendo la matriz enumerada (como las respuestas anteriores). Pero recuerde que al acceder y eliminar los elementos de las otras matrices, no es necesario revertirlos.
Like so, (one can copy and paste this on Playground) var a = ["a", "b", "c", "d"] var b = [1, 2, 3, 4] var c = ["!", "@", "#", "$"] // remove c, 3, # for (index, ch) in a.enumerated().reversed() { print("CH: \(ch). INDEX: \(index) | b: \(b[index]) | c: \(c[index])") if ch == "c" { a.remove(at: index) b.remove(at: index) c.remove(at: index) } } print("-----") print(a) // ["a", "b", "d"] print(b) // [1, 2, 4] print(c) // ["!", "@", "$"]
fuente