Suppression d'un objet du tableau dans Swift 3

93

Dans mon application, j'ai ajouté un objet dans le tableau lors de la sélection de la cellule et de la désélection et de la suppression de l'objet lors de la sélection de cellule. J'ai utilisé ce code mais me donne une erreur.

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

Cela me donne 2 erreurs comme ça:

C-style for statement has been removed in Swift 3
Value of type '[Any]' has no member 'removeObject'
Kamlesh Shingarakhiya
la source
Vous pouvez utiliser un Set<Contact>Array plutôt qu'un Array. Pouvez-vous fournir plus d'informations sur votre objet de contact? Si vous l'avez fait vous-même, vous en aurez besoin pour vous conformer Hashableet Equatablepour le mettre dans un ensemble
Paulw11

Réponses:

166

L'équivalent Swift de NSMutableArray's removeObjectest:

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

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

si les objets sont uniques . Il n'y a aucun besoin de lancer NSArrayet d'utiliserindexOfObject:

L'API index(of:fonctionne également, mais cela entraîne un pont implicite inutile vers NSArray.

S'il y a plusieurs occurrences du même objet, utilisez filter. Cependant, dans les cas comme les tableaux de sources de données où un index est associé à un objet particulier, il firstIndex(ofest préférable car il est plus rapide que filter.

Mise à jour:

Dans Swift 4.2+, vous pouvez supprimer une ou plusieurs occurrences de betaavec removeAll(where:):

array.removeAll{$0 == "beta"}
vadian
la source
34
C'est la meilleure réponse, mais il est plus que stupide de ne pas avoir de suppression (objet: "beta").
zeeple
5
Je pense que ce .index(of: n'est disponible que si la collection contient des Equatabletypes.
Adam Waite
@AdamWaite Oui, mais cela s'applique également aux types Foundation.
vadian le
Ce n'est pas correct, que faire si vous avez plus d'une "bêta"? Cela ne fonctionne que si le tableau ne contient pas plus d'une occurrence. La bonne réponse consiste à utiliser un filtre ou à exécuter cette réponse dans un certain temps,while let index = array.index(of: "beta") { array.remove(at: index) }
juancazalla
@juancazalla Vous avez raison, mais dans le cas où le tableau peut contenir plus d'une occurrence, utilisez la filtersolution. Mais si les objets sont uniques, utilisez toujours index(ofparce que c'est beaucoup plus performant quefilter
vadian
72
var a = ["one", "two", "three", "four", "five"]

// Remove/filter item with value 'three'
a = a.filter { $0 != "three" }
Nyxee
la source
7
C'est la bonne solution Swift, qui utilise les avantages de syntaxe offerts par le langage.
Michael
1
Et si l'élément est un objet?
TomSawyer
@TomSawyer pour filtrer un objet, utilisez $ 0! ==
Mike Taverne
25

Pour Swift 3, vous pouvez utiliser index (où :) et inclure une fermeture qui fait la comparaison d'un objet dans le tableau ($ 0) avec tout ce que vous recherchez.

var array = ["alpha", "beta", "gamma"]
if let index = array.index(where: {$0 == "beta"}) {
  array.remove(at: index)
}
Mark Semsel
la source
cela fonctionnera-t-il si je souhaite supprimer plusieurs objets? comme (où: {$ 0 == "beta" || $ 0 == "gamma"})
Irshad Mohamed
16

Une autre solution intéressante et utile consiste à créer ce type d'extension:

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 cette façon, si vous avez votre tableau avec des objets personnalisés:

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
la source
1
Cela ne fonctionne que si le tableau ne contient pas plus d'une occurrence. La bonne réponse consiste à utiliser un filtre ou à exécuter cette réponse dans un certain temps. En tant qu'utilisateur de cette extension, je m'attends à ce qu'elle supprime toutes les occurrences et pas une seule
juancazalla
C'est bien, mais ça devrait être remove(element: Element)parce que dans Array, vous pouvez également stocker des types comme Int, Double - ce ne sont pas des objets.
Radek Wilczak
8

Dans Swift 5 , utilisez ceci Extension:

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

exemple:

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

Dans Swift 3 , utilisez ceci Extension:

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

exemple:

var array = ["alpha", "beta", "gamma"]
array.remove(element: "beta")
Mohsenasm
la source
6
  1. for var index = self.indexOfObject(object); index != NSNotFound; index = self.indexOfObject(object) est une boucle for dans le style C et a été supprimée

  2. Changez votre code en quelque chose comme ceci pour supprimer tous les objets similaires s'ils ont bouclé:

    let indexes = arrContacts.enumerated().filter { $0.element == contacts[indexPath.row] }.map{ $0.offset }
    for index in indexes.reversed() {
       arrContacts.remove(at: index)
    }
    
Tj3n
la source
énuméré -> filtre -> mapper et supprimer (at) est une solution intelligente. Recommander celui-ci
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)
}
Sergey Di
la source
3

La solution en une ligne correcte et fonctionnelle pour supprimer un objet unique (nommé "objectToRemove") d'un tableau de ces objets (nommé "array") dans Swift 3 est:

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

Essayez ceci dans Swift 3

array.remove(at: Index)

Au lieu de

array.removeAtIndex(index)

Mise à jour

"Declaration is only valid at file scope".

Assurez-vous que l'objet est dans la portée. Vous pouvez donner une portée "interne", qui est par défaut.

index(of:<Object>) pour travailler, la classe doit se conformer à Equatable

Dili
la source
1

Dans Swift 3 et 4

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

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

Depuis Swift 4.2, vous pouvez utiliser une approche plus avancée (plus rapide et plus efficace en mémoire)

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

au lieu de

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

En savoir plus ici

yoAlex5
la source
1

Extension pour la baie pour le faire facilement et permettre le chaînage pour Swift 4.2 et plus:

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
la source
Les étiquettes d'argument '(où :)' ne correspondent à aucune surcharge disponible
jeet.chanchawat
1
@ jeet.chanchawat bien probablement différente version rapide alors ... Oh cette question était pour 3? Eh bien, je pense que j'avais 4.2 au moment de la rédaction, mais je ne me souviens pas maintenant, je le vérifierai plus tard, cela a définitivement fonctionné pour moi
Renetik
0

C'est la réponse officielle pour trouver l'index d'un objet spécifique, alors vous pouvez facilement supprimer n'importe quel objet en utilisant cet index:

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"]

Voici le lien: https://developer.apple.com/documentation/swift/array/2994720-firstindex

Mahesh Cheliya
la source
0

C'est ce que j'ai utilisé (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)

Résultats:

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

Important: le tableau à partir duquel vous supprimez des éléments doit contenir des éléments équatable (tels que des objets, des chaînes, des nombres, etc.)

Andrew Kingdom
la source