3
votes

Somme du tableau contenant la classe personnalisée (Swift)

Je cherche un moyen d'obtenir la somme des valeurs des classes qui sont contenues dans un tableau. Ma configuration est la suivante:

var sumArray = [Int]()
for object in array {
    sumArray.append(object.value!)
}
let sum = sumArray.reduce(0, +)

let object1 = CustomClass(value: 2)
let object2 = CustomClass(value: 4)
let object3 = CustomClass(value: 8)

let array: [CustomClass] = [object1, object2, object3]

Ma solution actuelle est la suivante:

class CustomClass {
    var value: Int?
    init(value: Int) {
       self.value = value
    }
}

Le problème est que cela devient très complexe avec des classes avec beaucoup d'autres valeurs, est-ce que quelqu'un connaît une meilleure solution?


3 commentaires

Lorsque vous dites «très complexe avec des classes avec de nombreuses autres valeurs», cela signifie-t-il que vous essayez également d'inclure des valeurs de différents types de classes dans l'opération de somme?


Oui en effet. En fait, ma classe contient le type Int et Date mais le type de date n'est pas censé être "fusionné".


@AndreasSchultz Je ne vois rien de complexe jusqu'à présent. Vous devez d'une manière ou d'une autre convertir les objets en un nombre (ce que vous faites déjà, bien que .map soit une meilleure solution) et ensuite simplement additionner les nombres.


3 Réponses :


2
votes

Vous pouvez utiliser une seule réduction sur tableau.

let sumOfValues = array.reduce({$0 += ($1.value ?? 0)})


4 commentaires

Il n'est pas nécessaire d'utiliser réduire pour cela. réduire (0) {0 $ + (1 $ valeur ?? 0)}


@LeoDabus vous avez raison, il n'y a pas besoin d'utiliser reduction (into:, _ :) , mais je ne vois pas non plus l'avantage d'utiliser reduction (_:, _ :) dessus


Il y a mais moi pas le bon pour vous l'expliquer. Avant l'implémentation du reduction (into :) dans Swift 4, il était parfois nécessaire de déclarer le résultat comme variable pour pouvoir le changer à l'intérieur de la fermeture. si vous n'avez pas besoin de le changer, utilisez simplement la réduction et retournez la somme result plus l'élément.


Reprise Si vous utilisez la méthode de réduction simple, il n'y a pas de variables juste des constantes à l'intérieur de votre fermeture



2
votes

Vous pouvez compactMap votre tableau de classe personnalisée en tableau d'entiers, puis réduire ce tableau à sa somme. Comme,

let sum = array.lazy.compactMap { $0.value }
            .reduce(0, +)


5 commentaires

utiliser des fermetures de fin, vous pouvez simplifier en .reduce (0, +)


Btw, vous pouvez également utiliser compactMap pour supprimer simplement nil au lieu d'ajouter des zéros array.compactMap ({$ 0.value}). Reduction (0, +)


Je mettrais un paresseux là-dedans, pour ignorer l'allocation de tableau intermédiaire à la suite de compactMap


@Alexander Je me demande comment faire ça. Est-ce comme lazy var sum = array.compactMap {$ 0.value} .reduce (0, +) ??


Non non, l'attribut lazy rend l'expression calculée à la première requête. Cela concerne toujours le tableau intermédiaire. Au lieu de cela, vous utilisez la propriété calculée lazy du tableau, qui renvoie une vue différée qui garde la trace des opérations que vous souhaitez effectuer, sans les exécuter jusqu'à ce que le résultat soit nécessaire. array.lazy.compactMap {$ 0.value} .reduce (0, +)



1
votes

Je créerais un protocole pour votre classe ou vos structures contenant une valeur. Et changez sa déclaration en non facultative.

let object1 = CustomClass(value: 2)
let object2 = CustomClass(value: 4)
let object3 = CustomClass(value: 8)

let objects = [object1, object2, object3]

let sum = objects.sum   // 14

Ensuite, vous devrez rendre votre classe conforme à ce protocole:

extension Collection where Element: Valueable {
    var sum: Int {
        return reduce(0) { $0 + $1.value }
    }
} 

Vous pouvez maintenant étendez le protocole de collecte avec une propriété d'instance en lecture seule pour renvoyer la somme de tous les éléments de votre tableau.

class CustomClass: Valueable {
    let value: Int
    init(value: Int) {
        self.value = value
    }
}

protocol Valueable {
    var value: Int { get }
}


0 commentaires