web-dev-qa-db-fra.com

Supprimer du tableau lors de l'énumération dans Swift?

Je veux énumérer un tableau dans Swift et supprimer certains éléments. Je me demande si cela est sans danger et, sinon, comment je suis censé y parvenir.

Actuellement, je ferais ceci:

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

Dans Swift 2, ceci est assez facile avec enumerate et reverse.

var a = [1,2,3,4,5,6]
for (i,num) in a.enumerate().reverse() {
    a.removeAtIndex(i)
}
print(a)

Voir mon swiftstub ici: http://swiftstub.com/944024718/?v=beta

63
Johnston

Vous pourriez envisager la méthode filter:

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

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

Le paramètre de filter est simplement une fermeture qui prend une instance de type tableau (dans ce cas, String) et retourne un Bool. Lorsque le résultat est true, l'élément est conservé, sinon l'élément est filtré.

55
Matteo Piombo

Dans Swift 3 et 4, ce serait:

Avec des chiffres, selon la réponse de Johnston:

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

Avec chaînes comme question du PO:

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

for (i,str) in b.enumerated().reversed()
{
    if str == "c"
    {
        b.remove(at: i)
    }
}
print(b)

Cependant, maintenant dans Swift 4.2 ou version ultérieure, il existe un moyen encore meilleur et plus rapide qui avait été recommandé par Apple dans WWDC2018:

var c = ["a", "b", "c", "d", "e", "f"]
c.removeAll(where: {$0 == "c"})
print(c)

Cette nouvelle manière présente plusieurs avantages:

  1. C'est plus rapide que les implémentations avec filter.
  2. Il supprime la nécessité d'inverser les tableaux.
  3. Il supprime les éléments sur place et met donc à jour le tableau d'origine au lieu d'allouer et de retourner un nouveau tableau.
32
jvarela

Lorsqu'un élément d'un certain index est supprimé d'un tableau, la position (et l'index) de tous les éléments suivants est modifiée, car ils reculent d'une position.

Le meilleur moyen est donc de naviguer dans le tableau dans l'ordre inverse - et dans ce cas, je suggère d'utiliser une boucle for traditionnelle:

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

Cependant, à mon avis, la meilleure approche consiste à utiliser la méthode filter, décrite par @perlfly dans sa réponse.

13
Antonio

Non, il est dangereux de muter des tableaux pendant l'énumération, votre code va planter.

Si vous voulez supprimer seulement quelques objets, vous pouvez utiliser la fonction filter.

4
Starscream

Créez un tableau mutable pour stocker les éléments à supprimer puis, après l'énumération, supprimez ces éléments de l'original. Vous pouvez également créer une copie du tableau (immuable), l'énumérer et supprimer les objets (non par index) de l'original lors de l'énumération.

2
Wain

Je recommande de définir les éléments sur nil lors de l'énumération, puis de supprimer tous les éléments vides à l'aide de la méthode array () de array.

1
freele