web-dev-qa-db-fra.com

Rechercher un élément et modifier la valeur dans un tableau d'objets personnalisés - Swift

J'ai cette classe

class InboxInterests {

    var title = ""
    var eventID = 0
    var count = ""
    var added = 0

    init(title : String, eventID : NSInteger, count: String, added : NSInteger) {
        self.title = title
        self.eventID = eventID
        self.count = count
        self.added = added

    }
}

Et je l'utilise comme ça

var array: [InboxInterests] = [InboxInterests]()

Ajouter un item

let post = InboxInterests(title: "test",eventID : 1, count: "test", added: 0)
self.array.append(post)

Je veux trouver l'index par la clé eventID et changer la valeur de la clé added dans le même index

Comment est-ce possible?

25
Utku Dalmaz

Utilisez le filtre et commencez par trouver la valeur:

array.filter({$0.eventID == id}).first?.added = value

En cela vous:

  1. filtrer le tableau en fonction des éléments correspondant à l'ID d'événement
  2. choisir le premier résultat, le cas échéant
  3. puis définir la valeur

EDIT: Dans Swift 3, vous pouvez vous épargner quelques caractères

array.first({$0.eventID == id})?.added = value

EDIT: Swift 4.2:

array.first(where: { $0.eventID == id })?.added = value
array.filter {$0.eventID == id}.first?.added = value
33
Luke

Pour moi, la réponse ci-dessus n'a pas fonctionné. Donc, ce que j'ai fait était d'abord de trouver l'index de l'objet que je veux remplacer, puis en utilisant l'index, le remplacer par la nouvelle valeur

if let row = self.upcoming.index(where: {$0.eventID == id}) {
       array[row] = newValue
}

Dans Swift 5.0:

if let row = self.upcoming.firstIndex(where: {$0.eventID == id}) {
       array[row] = newValue
}
52

L'opérateur de filtre n'est pas le meilleur dans ce cas, il fonctionne pour certains d'entre vous car les classes sont passées par référence.

Explication: (vous pouvez copier le code suivant dans un terrain de jeu si vous souhaitez le vérifier).

class Book {
    let id: Int
    var title = "default"

    init (id: Int) {
        self.id = id
    }
}
var arrayBook = [Book]()
arrayBook.append(Book(id: 0))
arrayBook.append(Book(id:1))
arrayBook.forEach { book in
    print(book.title)
}

arrayBook.filter{ $0.id == 1 }.first?.title = "modified"

arrayBook.forEach { book in
    print(book.title)
}

Les tableaux sont copiés par valeur et non par référence. Ainsi, lorsque vous utilisez le filtre, vous créez un nouveau tableau (différent du premier), mais lorsque vous modifiez le nouveau, le premier est également modifié car les deux pointent vers la même classe ( classées sont passées par référence), donc après le filtre votre tableau aura changé et le nouveau sera désalloué. Donc, dans ce cas, il affichera "défaut", "par défaut" puis "par défaut," modifié ".

Que se passe-t-il si vous changez class pour struct, la valeur sera transmise par valeur non référence afin que vous ayez 2 tableaux en mémoire avec des valeurs différentes, donc si vous passez par arrayBooks à nouveau, il sera imprimé avant le filtre "default", "default", puis "default", "default" à nouveau. Parce que lorsque vous utilisez le filtre, vous créez et modifiez un nouveau tableau qui sera désalloué si vous ne le stockez pas).

La solution utilise map, créant un nouveau tableau avec toutes les valeurs mais avec les éléments modifiés ou les champs souhaités, puis remplaçons notre tableau par le nouveau. Ceci affichera "défaut", "défaut" avant la carte, puis "défaut", "modifié"

Cela fonctionnera avec les structures, les classes et tout ce que vous voulez :).

struct Book {
    let id: Int
    var title = "default"

    init (id: Int) {
        self.id = id
    }
}
var arrayBook = [Book]()
arrayBook.append(Book(id: 0))
arrayBook.append(Book(id:1))
arrayBook.forEach { book in
    print(book.title)
}

arrayBook = arrayBook.map{
    var mutableBook = $0
    if $0.id == 1 {
        mutableBook.title = "modified"
    }
    return mutableBook
}

arrayBook.forEach { book in
    print(book.title)
}
14