Rimozione di oggetti dall'array in Swift 3


93

Nella mia applicazione ho aggiunto un oggetto nella matrice quando si seleziona la cella e deseleziono e rimuovi l'oggetto quando si riseleziona la cella. Ho usato quel codice ma mi da errore.

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])
    }
}

Mi dà 2 errori come questo:

C-style for statement has been removed in Swift 3
Value of type '[Any]' has no member 'removeObject'

Puoi usare un Set<Contact>piuttosto che un Array. Potete fornire maggiori informazioni sul vostro oggetto di contatto? Se l'hai fatto da solo, avrai bisogno che sia conforme Hashablee Equatableper metterlo in un set
Paulw11

Risposte:


166

L'equivalente di Swift di NSMutableArrays removeObjectè:

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

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

se gli oggetti sono unici . Non è affatto necessario trasmettere NSArraye utilizzareindexOfObject:

Anche l'API index(of:funziona, ma questo causa un cast di bridge implicito non necessario a NSArray.

Se sono presenti più occorrenze dello stesso oggetto, utilizzare filter. Tuttavia, in casi come gli array di origini dati in cui un indice è associato a un particolare oggetto firstIndex(ofè preferibile perché è più veloce di filter.

Aggiornare:

In Swift 4.2+ puoi rimuovere una o più occorrenze di betacon removeAll(where:):

array.removeAll{$0 == "beta"}

34
Questa è la risposta migliore, ma non è stupido non avere una rimozione (oggetto: "beta").
zeeple

5
Penso che .index(of: sia disponibile solo se la raccolta contiene Equatabletipi.
Adam Waite

@AdamWaite Sì, ma questo vale anche per i tipi Foundation.
vadian

Questo non è corretto, cosa succede se hai più di una "beta"? Funziona solo se l'array non contiene più di un'occorrenza. La risposta giusta è usare un filtro o eseguire questa risposta tra un po ',while let index = array.index(of: "beta") { array.remove(at: index) }
juancazalla

@juancazalla Hai ragione, ma nel caso in cui l'array possa contenere più occorrenze usa la filtersoluzione. Ma se gli oggetti sono unici, index(offilter
usali

72
var a = ["one", "two", "three", "four", "five"]

// Remove/filter item with value 'three'
a = a.filter { $0 != "three" }

7
Questa è la soluzione Swift corretta, che utilizza i vantaggi di sintassi offerti dal linguaggio.
Michael

1
E se l'articolo fosse un oggetto?
TomSawyer

@TomSawyer per filtrare un oggetto, usa $ 0! ==
Mike Taverne

25

Per Swift 3, puoi usare index (dove :) e includere una chiusura che fa il confronto di un oggetto nell'array ($ 0) con quello che stai cercando.

var array = ["alpha", "beta", "gamma"]
if let index = array.index(where: {$0 == "beta"}) {
  array.remove(at: index)
}

funzionerà se voglio rimuovere più oggetti? like (dove: {$ 0 == "beta" || $ 0 == "gamma"})
Irshad Mohamed

16

Un'altra soluzione simpatica e utile è creare questo tipo di estensione:

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
    }

}

In questo modo, se hai il tuo array con oggetti personalizzati:

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) 

1
Funziona solo se l'array non contiene più di un'occorrenza. La risposta giusta è usare un filtro o eseguire questa risposta tra un po '. Come utente di questa estensione, mi aspetto che rimuova tutte le occorrenze e non solo una
juancazalla

È bello, ma dovrebbe essere remove(element: Element)perché in Array puoi memorizzare anche tipi come Int, Double - non sono oggetti.
Radek Wilczak

8

In Swift 5 , usa questo Extension:

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

esempio:

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

In Swift 3 , usa questo Extension:

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

esempio:

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

6
  1. for var index = self.indexOfObject(object); index != NSNotFound; index = self.indexOfObject(object) è per loop in C-style ed è stato rimosso

  2. Cambia il tuo codice in qualcosa di simile per rimuovere tutti gli oggetti simili se è stato eseguito in loop:

    let indexes = arrContacts.enumerated().filter { $0.element == contacts[indexPath.row] }.map{ $0.offset }
    for index in indexes.reversed() {
       arrContacts.remove(at: index)
    }
    

enumerato -> filtro -> mappa e rimuovi (at) è una soluzione intelligente. Consiglia questo
Ryan X

4

Swift 4

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

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

3

La soluzione su una riga corretta e funzionante per eliminare un oggetto univoco (denominato "objectToRemove") da un array di questi oggetti (denominato "array") in Swift 3 è:

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

1

Prova questo in Swift 3

array.remove(at: Index)

Invece di

array.removeAtIndex(index)

Aggiornare

"Declaration is only valid at file scope".

Assicurati che l'oggetto sia nell'ambito. Puoi assegnare l'ambito "interno", che è l'impostazione predefinita.

index(of:<Object>) per funzionare, la classe dovrebbe conformarsi Equatable


1

In Swift 3 e 4

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

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

Da Swift 4.2 puoi utilizzare un approccio più avanzato (più veloce ed efficiente in termini di memoria)

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

invece di

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

Leggi di più qui


1

Estensione per array per farlo facilmente e consentire il concatenamento per Swift 4.2 e versioni successive:

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
    }
}

Le etichette degli argomenti '(dove :)' non corrispondono ad alcun sovraccarico disponibile
jeet.chanchawat

1
@ jeet.chanchawat beh, probabilmente una versione rapida diversa allora ... Oh questa domanda era per 3? Beh, penso di aver avuto 4.2 al momento della scrittura, ma non ricordo ora, lo controllerò più tardi, ha sicuramente funzionato per me
Renetik


0

Questo è quello che ho usato (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)

Risultati:

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

Importante: l'array da cui rimuovi gli elementi deve contenere elementi Equatable (come oggetti, stringhe, numeri, ecc.)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.