ios électrique Extension de tableau pour supprimer un objet par valeur



pose tableau electrique norme (11)

extension Array {
    func removeObject<T where T : Equatable>(object: T) {
        var index = find(self, object)
        self.removeAtIndex(index)
    }
}

Cependant, j'obtiens une erreur sur var index = find(self, object)

'T' n'est pas convertible en 'T'

J'ai aussi essayé avec cette méthode la signature: func removeObject(object: AnyObject) , cependant, j'ai la même erreur:

'AnyObject' n'est pas convertible en 'T'

Quelle est la bonne façon de faire cela?


En utilisant indexOf au lieu d'un for ou enumerate :

extension Array where Element: Equatable {

   mutating func removeElement(element: Element) -> Element? {
      if let index = indexOf(element) {
         return removeAtIndex(index)
      }
      return nil
   }

   mutating func removeAllOccurrencesOfElement(element: Element) -> Int {
       var occurrences = 0
       while true {
          if let index = indexOf(element) {
             removeAtIndex(index)
             occurrences++
          } else {
             return occurrences
          }
       }
   }   
}

J'ai finalement fini avec le code suivant.

extension Array where Element: Equatable {

    mutating func remove<Element: Equatable>(item: Element) -> Array {
        self = self.filter { $0 as? Element != item }
        return self
    }

}

À partir de Swift 2 , ceci peut être réalisé avec une méthode d'extension de protocole . removeObject() est défini comme une méthode sur tous les types conformes à RangeReplaceableCollectionType (en particulier sur Array ) si les éléments de la collection sont Equatable :

extension RangeReplaceableCollectionType where Generator.Element : Equatable {

    // Remove first collection element that is equal to the given `object`:
    mutating func removeObject(object : Generator.Element) {
        if let index = self.indexOf(object) {
            self.removeAtIndex(index)
        }
    }
}

Exemple:

var ar = [1, 2, 3, 2]
ar.removeObject(2)
print(ar) // [1, 3, 2]

Mise à jour pour Swift 2 / Xcode 7 beta 2: Comme la vitesse airspeed noté dans les commentaires, il est maintenant possible d'écrire une méthode sur un type générique qui est plus restrictif sur le template, donc la méthode pourrait maintenant être définie comme une extension de Array :

extension Array where Element : Equatable {

    // ... same method as above ...
}

L'extension de protocole a encore l'avantage d'être applicable à un plus grand nombre de types.

Mise à jour pour Swift 3:

extension Array where Element: Equatable {

    // Remove first collection element that is equal to the given `object`:
    mutating func remove(object: Element) {
        if let index = index(of: object) {
            remove(at: index)
        }
    }
}

J'ai réussi à le faire fonctionner avec:

extension Array {
    mutating func removeObject<T: Equatable>(object: T) {
        var index: Int?
        for (idx, objectToCompare) in enumerate(self) {
            let to = objectToCompare as T
            if object == to {
                index = idx
            }
        }

        if(index) {
            self.removeAtIndex(index!)
        }
    }
}

Il existe une autre possibilité de supprimer un élément d'un tableau sans risque d'utilisation dangereuse, car le type générique de l'objet à supprimer ne peut pas être le même que le type du tableau. L'utilisation d'options n'est pas la meilleure façon d'y aller car elles sont très lentes. Vous pouvez donc utiliser une fermeture comme elle est déjà utilisée lors du tri d'un tableau par exemple.

//removes the first item that is equal to the specified element
mutating func removeFirst(element: Element, equality: (Element, Element) -> Bool) -> Bool {
    for (index, item) in enumerate(self) {
        if equality(item, element) {
            self.removeAtIndex(index)
            return true
        }
    }
    return false
}

Lorsque vous étendez la classe Array avec cette fonction, vous pouvez supprimer des éléments en procédant comme suit:

var array = ["Apple", "Banana", "Strawberry"]
array.removeFirst("Banana") { $0 == $1 } //Banana is now removed

Cependant, vous pouvez même supprimer un élément uniquement s'il a la même adresse mémoire (uniquement pour les classes conformes au protocole AnyObject , bien sûr):

let date1 = NSDate()
let date2 = NSDate()
var array = [date1, date2]
array.removeFirst(NSDate()) { $0 === $1 } //won't do anything
array.removeFirst(date1) { $0 === $1 } //array now contains only 'date2'

La bonne chose est que vous pouvez spécifier le paramètre à comparer. Par exemple lorsque vous avez un tableau de tableaux, vous pouvez spécifier la fermeture d'égalité comme { $0.count == $1.count } et le premier tableau ayant la même taille que celui à supprimer est supprimé du tableau.

Vous pouvez même raccourcir l'appel de fonction en ayant la fonction comme mutating func removeFirst(equality: (Element) -> Bool) -> Bool , puis remplacer l'if-evaluation par l' equality(item) et appeler la fonction par array.removeFirst({ $0 == "Banana" }) par exemple.


Après avoir lu tout ce qui précède, à mon avis la meilleure réponse est:

func arrayRemovingObject<U: Equatable>(object: U, # fromArray:[U]) -> [U] {
  return fromArray.filter { return $0 != object }
}

Échantillon:

var myArray = ["Dog", "Cat", "Ant", "Fish", "Cat"]
myArray = arrayRemovingObject("Cat", fromArray:myArray )

Swift 2 (xcode 7b4) extension de tableau:

extension Array where Element: Equatable {  
  func arrayRemovingObject(object: Element) -> [Element] {  
    return filter { $0 != object }  
  }  
}  

Échantillon:

var myArray = ["Dog", "Cat", "Ant", "Fish", "Cat"]
myArray = myArray.arrayRemovingObject("Cat" )

Mise à jour Swift 3.1

Revenons à cela maintenant que Swift 3.1 est sorti. Voici une extension qui fournit des variantes exhaustives, rapides, mutantes et créatrices.

extension Array where Element:Equatable {
    public mutating func remove(_ item:Element ) {
        var index = 0
        while index < self.count {
            if self[index] == item {
                self.remove(at: index)
            } else {
                index += 1
            }
        }
    }

    public func array( removing item:Element ) -> [Element] {
        var result = self
        result.remove( item )
        return result
    }
}

Échantillons:

// Mutation...
      var array1 = ["Cat", "Dog", "Turtle", "Cat", "Fish", "Cat"]
      array1.remove("Cat")
      print(array1) //  ["Dog", "Turtle", "Socks"]

// Creation...
      let array2 = ["Cat", "Dog", "Turtle", "Cat", "Fish", "Cat"]
      let array3 = array2.array(removing:"Cat")
      print(array3) // ["Dog", "Turtle", "Fish"]

Mise en œuvre dans Swift 2:

extension Array {
  mutating func removeObject<T: Equatable>(object: T) -> Bool {
    var index: Int?
    for (idx, objectToCompare) in self.enumerate() {
      if let toCompare = objectToCompare as? T {
        if toCompare == object {
          index = idx
          break
        }
      }
    }
    if(index != nil) {
      self.removeAtIndex(index!)
      return true
    } else {
      return false
    }
  }
}

Avec l'utilisation des extensions de protocole dans swift 2.0

extension _ArrayType where Generator.Element : Equatable{
    mutating func removeObject(object : Self.Generator.Element) {
        while let index = self.indexOf(object){
            self.removeAtIndex(index)
        }
    }
}

Avec les extensions de protocole, vous pouvez le faire,

extension Array where Element: Equatable {
    mutating func remove(object: Element) {
        if let index = indexOf({ $0 == object }) {
            removeAtIndex(index)
        }
    }
}

Même fonctionnalité pour les classes,

Swift 2

extension Array where Element: AnyObject {
    mutating func remove(object: Element) {
        if let index = indexOf({ $0 === object }) {
            removeAtIndex(index)
        }
    }
}

Swift 3

extension Array where Element: AnyObject {
    mutating func remove(object: Element) {
        if let index = index(where: { $0 === object }) {
             remove(at: index)
        }
    }
}

Mais si une classe implémente Equatable, elle devient ambiguë et le compilateur donne une erreur.


J'ai réussi à supprimer un [String:AnyObject] d'un tableau [[String:AnyObject]] en implémentant un compte en dehors d'une boucle for pour représenter l'index puisque .find et .filter ne sont pas compatibles avec [String:AnyObject] .

let additionValue = productHarvestChoices[trueIndex]["name"] as! String
var count = 0
for productHarvestChoice in productHarvestChoices {
  if productHarvestChoice["name"] as! String == additionValue {
    productHarvestChoices.removeAtIndex(count)
  }
  count = count + 1
}

Vous ne pouvez pas écrire une méthode sur un type générique plus restrictif sur le modèle.

NOTE : à partir de Swift 2.0, vous pouvez maintenant écrire des méthodes plus restrictives sur le template. Si vous avez mis à jour votre code vers la version 2.0, consultez les autres réponses plus bas pour connaître les nouvelles options permettant d'implémenter cette extension.

La raison pour laquelle vous obtenez l'erreur 'T' is not convertible to 'T' est que vous définissez en fait un nouveau T dans votre méthode qui n'est pas du tout lié à l'original T. Si vous vouliez utiliser T dans votre méthode, vous peut le faire sans le spécifier sur votre méthode.

La raison pour laquelle vous obtenez la deuxième erreur 'AnyObject' is not convertible to 'T' est que toutes les valeurs possibles pour T ne sont pas toutes les classes. Pour qu'une instance soit convertie en AnyObject, elle doit être une classe (elle ne peut pas être une structure, une énumération, etc.).

Votre meilleur pari est d'en faire une fonction qui accepte le tableau en tant qu'argument:

func removeObject<T : Equatable>(object: T, inout fromArray array: [T]) {
}

Ou au lieu de modifier le tableau d'origine, vous pouvez rendre votre méthode plus sûre et réutilisable en retournant une copie:

func arrayRemovingObject<T : Equatable>(object: T, fromArray array: [T]) -> [T] {
}

Comme alternative que je ne recommande pas, vous pouvez faire en sorte que votre méthode échoue silencieusement si le type stocké dans le tableau ne peut pas être converti en modèle de méthodes (c'est-à-dire équivalent). (Pour plus de clarté, j'utilise U au lieu de T pour le modèle de la méthode):

extension Array {
    mutating func removeObject<U: Equatable>(object: U) {
        var index: Int?
        for (idx, objectToCompare) in enumerate(self) {
            if let to = objectToCompare as? U {
                if object == to {
                    index = idx
                }
            }
        }

        if(index != nil) {
            self.removeAtIndex(index!)
        }
    }
}

var list = [1,2,3]
list.removeObject(2) // Successfully removes 2 because types matched
list.removeObject("3") // fails silently to remove anything because the types don't match
list // [1, 3]

Modifier Pour surmonter l'échec silencieux, vous pouvez retourner le succès en tant que booléen:

extension Array {
  mutating func removeObject<U: Equatable>(object: U) -> Bool {
    for (idx, objectToCompare) in self.enumerate() {  //in old swift use enumerate(self) 
      if let to = objectToCompare as? U {
        if object == to {
          self.removeAtIndex(idx)
          return true
        }
      }
    }
    return false
  }
}
var list = [1,2,3,2]
list.removeObject(2)
list
list.removeObject(2)
list




swift