Eliminar objeto de la matriz en Swift 3

93

En mi aplicación agregué un objeto en la matriz cuando seleccioné la celda y deseleccioné y eliminé el objeto cuando volví a seleccionar la celda. Usé ese código pero me da un error.

extension Array {
    func indexOfObject(object : AnyObject) -> NSInteger {
        return (self as NSArray).indexOfObject(object)
    }

    mutating func removeObject(object : AnyObject) {
        for var index = self.indexOfObject(object); index != NSNotFound; index = self.indexOfObject(object) {
            self.removeAtIndex(index)
        }
    }
}

class MyViewController: UITableViewController {
    var arrContacts: [Any] = []
    var contacts: [Any] = []

    func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
        arrContacts.removeObject(contacts[indexPath.row])
    }
}

Me da 2 errores como ese:

C-style for statement has been removed in Swift 3
Value of type '[Any]' has no member 'removeObject'
Kamlesh Shingarakhiya
fuente
Puede utilizar un en Set<Contact>lugar de un Array. ¿Puede proporcionar más información sobre su objeto de contacto? Si lo ha hecho usted mismo, lo necesitará para adaptarse Hashabley Equatablepara ponerlo en un conjunto
Paulw11

Respuestas:

166

El Swift equivalente a NSMutableArray's removeObjectes:

var array = ["alpha", "beta", "gamma"]

if let index = array.firstIndex(of: "beta") {
    array.remove(at: index)
}

si los objetos son únicos . No hay ninguna necesidad de lanzar NSArrayy usarindexOfObject:

La API index(of:también funciona, pero esto provoca una conversión de puente implícita innecesaria a NSArray.

Si hay varias apariciones del mismo objeto, utilice filter. Sin embargo, en casos como los arreglos de fuentes de datos, donde un índice está asociado con un objeto en particular, firstIndex(ofes preferible porque es más rápido que filter.

Actualizar:

En Swift 4.2+ puede eliminar una o varias apariciones de betacon removeAll(where:):

array.removeAll{$0 == "beta"}
vadian
fuente
34
Esta es la mejor respuesta, pero es más que estúpido no tener una eliminación (objeto: "beta").
zeeple
5
Creo que .index(of: solo está disponible si la colección contiene Equatabletipos.
Adam Waite
@AdamWaite Sí, pero esto se aplica también a los tipos Foundation.
vadian
Esto no es correcto, ¿qué pasa si tienes más de una "beta"? Esto solo funciona si la matriz no contiene más de una aparición. La respuesta correcta es usar un filtro o ejecutar esta respuesta en un tiempo,while let index = array.index(of: "beta") { array.remove(at: index) }
juancazalla
@juancazalla Tienes razón, pero en el caso de que la matriz pueda contener más de una ocurrencia, usa la filtersolución. Pero si los objetos son únicos, utilícelos siempre index(ofporque es mucho más filter
eficaz
72
var a = ["one", "two", "three", "four", "five"]

// Remove/filter item with value 'three'
a = a.filter { $0 != "three" }
nyxee
fuente
7
Esa es la solución Swift correcta, que hace uso de las ventajas de sintaxis que ofrece el lenguaje.
Michael
1
¿Qué pasa si el artículo es un objeto?
TomSawyer
@TomSawyer para filtrar un objeto, use $ 0! ==
Mike Taverne
25

Para Swift 3, puede usar index (donde :) e incluir un cierre que haga la comparación de un objeto en la matriz ($ 0) con lo que esté buscando.

var array = ["alpha", "beta", "gamma"]
if let index = array.index(where: {$0 == "beta"}) {
  array.remove(at: index)
}
Mark Semsel
fuente
¿Funcionará esto si quiero eliminar varios objetos? like (donde: {$ 0 == "beta" || $ 0 == "gamma"})
Irshad Mohamed
16

Otra buena y útil solución es crear este tipo de extensión:

extension Array where Element: Equatable {

    @discardableResult mutating func remove(object: Element) -> Bool {
        if let index = index(of: object) {
            self.remove(at: index)
            return true
        }
        return false
    }

    @discardableResult mutating func remove(where predicate: (Array.Iterator.Element) -> Bool) -> Bool {
        if let index = self.index(where: { (element) -> Bool in
            return predicate(element)
        }) {
            self.remove(at: index)
            return true
        }
        return false
    }

}

De esta manera, si tiene su matriz con objetos personalizados:

let obj1 = MyObject(id: 1)
let obj2 = MyObject(id: 2)
var array: [MyObject] = [obj1, obj2]

array.remove(where: { (obj) -> Bool in
    return obj.id == 1
})
// OR
array.remove(object: obj2) 
Luca Davanzo
fuente
1
Esto solo funciona si la matriz no contiene más de una aparición. La respuesta correcta es usar un filtro o ejecutar esta respuesta en un tiempo. Como usuario de esta extensión, espero que elimine todas las ocurrencias y no solo una
juancazalla
Es bueno, pero debería serlo remove(element: Element)porque en Array también puede almacenar tipos como Int, Double, no son objetos.
Radek Wilczak
8

En Swift 5 , usa esto Extension:

extension Array where Element: Equatable{
    mutating func remove (element: Element) {
        if let i = self.firstIndex(of: element) {
            self.remove(at: i)
        }
    }
}

ejemplo:

var array = ["alpha", "beta", "gamma"]
array.remove(element: "beta")

En Swift 3 , usa esto Extension:

extension Array where Element: Equatable{
    mutating func remove (element: Element) {
        if let i = self.index(of: element) {
            self.remove(at: i)
        }
    }
}

ejemplo:

var array = ["alpha", "beta", "gamma"]
array.remove(element: "beta")
Mohsenasm
fuente
6
  1. for var index = self.indexOfObject(object); index != NSNotFound; index = self.indexOfObject(object) es para bucle en estilo C y se ha eliminado

  2. Cambie su código a algo como esto para eliminar todos los objetos similares si se han repetido:

    let indexes = arrContacts.enumerated().filter { $0.element == contacts[indexPath.row] }.map{ $0.offset }
    for index in indexes.reversed() {
       arrContacts.remove(at: index)
    }
    
Tj3n
fuente
enumerado -> filtrar -> mapear y eliminar (en) es una solución inteligente. Recomendar este
Ryan X
4

Rápido 4

var students = ["Kofi", "Abena", "Peter", "Kweku", "Akosua"]

if let index = students.firstIndex(where: { $0.hasPrefix("A") }) {
   students.remove(at: index)
}
Sergey Di
fuente
3

La solución de una línea correcta y funcional para eliminar un objeto único (llamado "objectToRemove") de una matriz de estos objetos (llamada "matriz") en Swift 3 es:

if let index = array.enumerated().filter( { $0.element === objectToRemove }).map({ $0.offset }).first {
   array.remove(at: index)
}
Joerg
fuente
1

Prueba esto en Swift 3

array.remove(at: Index)

En vez de

array.removeAtIndex(index)

Actualizar

"Declaration is only valid at file scope".

Asegúrese de que el objeto esté dentro del alcance. Puede dar alcance "interno", que es el predeterminado.

index(of:<Object>) para trabajar, la clase debe ajustarse a Equatable

Dili
fuente
1

En Swift 3 y 4

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

for (index, element) in array.enumerated().reversed() {
    array.remove(at: index)
}

Desde Swift 4.2 puede utilizar un enfoque más avanzado (más rápido y eficiente en memoria)

array.removeAll(where: { $0 == "c" })

en vez de

array = array.filter { !$0.hasPrefix("c") }

Leer más aquí

yoAlex5
fuente
1

Extensión para matriz para hacerlo fácilmente y permitir el encadenamiento para Swift 4.2 y versiones posteriores:

public extension Array where Element: Equatable {
    @discardableResult
    public mutating func remove(_ item: Element) -> Array {
        if let index = firstIndex(where: { item == $0 }) {
            remove(at: index)
        }
        return self
    }

    @discardableResult
    public mutating func removeAll(_ item: Element) -> Array {
        removeAll(where: { item == $0 })
        return self
    }
}
Renetik
fuente
Las etiquetas de argumento '(donde :)' no coinciden con ninguna sobrecarga disponible
jeet.chanchawat
1
@ jeet.chanchawat bueno, probablemente una versión rápida diferente entonces ... Oh, ¿esta pregunta era para 3? Bueno, creo que tenía 4.2 al momento de escribir este artículo, pero no recuerdo ahora, lo comprobaré más tarde, definitivamente funcionó para mí
Renetik
0

Esta es la respuesta oficial para encontrar el índice de un objeto específico, luego puede eliminar fácilmente cualquier objeto usando ese índice:

var students = ["Ben", "Ivy", "Jordell", "Maxime"]
if let i = students.firstIndex(of: "Maxime") {
     // students[i] = "Max"
     students.remove(at: i)
}
print(students)
// Prints ["Ben", "Ivy", "Jordell"]

Aquí está el enlace: https://developer.apple.com/documentation/swift/array/2994720-firstindex

Mahesh Cheliya
fuente
0

Esto es lo que he usado (Swift 5) ...

    extension Array where Element:Equatable
    {
        @discardableResult
        mutating func removeFirst(_ item:Any ) -> Any? {
            for index in 0..<self.count {
                if(item as? Element == self[index]) {
                    return self.remove(at: index)
                }
            }
            return nil
        }
        @discardableResult
        mutating func removeLast(_ item:Any ) -> Any? {
            var index = self.count-1
            while index >= 0 {
                if(item as? Element == self[index]) {
                    return self.remove(at: index)
                }
                index -= 1
            }
            return nil
        }
    }

    var arrContacts:[String] = ["A","B","D","C","B","D"]
    var contacts: [Any] = ["B","D"]
    print(arrContacts)
    var index = 1
    arrContacts.removeFirst(contacts[index])
    print(arrContacts)
    index = 0
    arrContacts.removeLast(contacts[index])
    print(arrContacts)

Resultados:

   ["A", "B", "D", "C", "B", "D"]
   ["A", "B", "C", "B", "D"]
   ["A", "B", "C", "D"]

Importante: La matriz de la que elimina elementos debe contener elementos Equatable (como objetos, cadenas, número, etc.)

Andrew Reino
fuente