[Résolu] Diviser un Array en Arrays en deux dimension

iLandesiLandes Membre
septembre 2017 modifié dans Objective-C, Swift, C, C++ #1

Bonjour,


 


J'ai le code suivant :



import UIKit

class Student: CustomStringConvertible {
    var name: String
    var level: String
    
    var description: String {
        return "\(level): \(name)"
    }
    
    init (name: String, level: String) {
        self.name = name
        self.level = level
    }
}

var students:[Student] = []
students.append(Student(name: "AAA", level: "CC"))
students.append(Student(name: "BBB", level: "CC"))
students.append(Student(name: "CCC", level: "AA"))
students.append(Student(name: "DDD", level: "CC"))
students.append(Student(name: "EEE", level: "AA"))
students.append(Student(name: "FFF", level: "CC"))
students.append(Student(name: "GGG", level: "BB"))

let studentsByLevel = students.sorted { (a, b) -> Bool in
    a.level < b.level
}

print (studentsByLevel)

Je souhaiterai de manière élégante transformer tableau d'étudiants en tableau à  deux dimensions en les regroupant par niveau. Pour obtenir quelque chose comme ça :



[[AA: CCC, AA: EEE],[BB: GGG], [CC: AAA, CC: BBB, CC: DDD, CC: FFF]]

Ne faite pas attention aux deux points, ils font parti de la description de la classe étudiant.


 


D'avance merci pour votre collaboration.


Mots clés:

Réponses


  • let listeAA = students.filter { $0.level == "AA" }
    let listeBB = students.filter { $0.level == "BB" }
    let listeCC = students.filter { $0.level == "CC" }

    print (listeAA)
    print (listeBB)
    print (listeCC)



    [AA: CCC, AA: EEE]
    [BB: GGG]
    [CC: AAA, CC: BBB, CC: DDD, CC: FFF]
  • Merci Draken pour ta proposition.


     


    J'y avais pensé mais cette solution suppose que l'on connaisse déjà  les niveaux qui existent


  • Bonjour,


     


    Pour connaà®tre les niveaux, quelque chose comme Set(students.map{$0.level}) devrait faire l'affaire ? (je ne suis pas devant xCode ou Playgrounds) et ne peux tester !


     


    Et ensuite, une boucle avec la proposition de Draken pour chaque niveau,


     


    Cordialement,


    Nicolas




  • Bonjour,


     


    Pour connaà®tre les niveaux, quelque chose comme Set(students.map{$0.level}) devrait faire l'affaire ? (je ne suis pas devant xCode ou Playgrounds) et ne peux tester !


     


    Et ensuite, une boucle avec la proposition de Draken pour chaque niveau,


     


    Cordialement,


    Nicolas




    Absolument. J'allais le suggérer pour compléter ma proposition initiale



    let listeNiveaux = Set(students.map { $0.level })
    print ("Niveaux : ", listeNiveaux)


     


    Niveaux :  ["CC", "BB", "AA"]


  • iLandesiLandes Membre
    septembre 2017 modifié #6

    Ca fonctionne merci Draken !


     


    Voici le code définitif pour ceux que ça intéresse:



    //: Playground - noun: a place where people can play

    import UIKit

    class Student: CustomStringConvertible {
        var name: String
        var level: String
        
        var description: String {
            return "\(level): \(name)"
        }
        
        init (name: String, level: String) {
            self.name = name
            self.level = level
        }
    }


    var students:[Student] = Array()
    students.append(Student(name: "AAA", level: "CC"))
    students.append(Student(name: "BBB", level: "CC"))
    students.append(Student(name: "CCC", level: "AA"))
    students.append(Student(name: "DDD", level: "CC"))
    students.append(Student(name: "EEE", level: "AA"))
    students.append(Student(name: "FFF", level: "CC"))
    students.append(Student(name: "GGG", level: "BB"))



    let levels = Set(students.map({ (student) in
        return student.level
    }))


    var studentsByLevel:[[Student]] = Array()
    for level in levels {
        let studentsInLevel: [Student] = students.filter({ (student) -> Bool in
            student.level == level
        })
        if studentsInLevel.count > 0 {
            studentsByLevel.append(studentsInLevel)
        }
    }

    print (studentsByLevel)

    Console :



    [CC: AAA, CC: BBB, CC: DDD, CC: FFF], [BB: GGG], [AA: CCC, AA: EEE]]
  • Allé pour rigoler :



    let studentsByLevel = students.lazy.reduce(into: [String: [Student]]()) { (acc, student) in
    if acc[student.level] != nil {
    acc[student.level]?.append(student)
    } else {
    acc[student.level] = [student]
    }
    }.map { $0.value }
  • On rigole mais ça compile pas, acc est immutable 


    ;D


  • DrakenDraken Membre
    septembre 2017 modifié #9

    Pyroh, pourquoi ce lazy ?


     


    EDIT : ok, je viens de lire la doc. C'est un attribut " sécurisé " du tableau à  utiliser quand on exécute une chaà®ne d'opérations complexe impliquant des .map, .filter et .reduce imbriqués les uns dans les autres. C'est clair que cette imbrication doit bien " secouer" la mémoire !


  • DrakenDraken Membre
    septembre 2017 modifié #10


    On rigole mais ça compile pas, acc est immutable 


    ;D




    Mais si, ça marche. Je viens de tester avec Xcode 9. Tu es encore sous Xcode 8 et Swift 3 ?


     


    EDIT : Je confirme, cela ne fonctionne pas avec Swift 3 et Xcode 8. C'est du pur Swift 4.

  • Xcode8, swift 3




  • Xcode8, swift 3




    Apple est passé officiellement à  Xcode 9 depuis .. cette nuit ! Tu dois avoir un petit badge rouge sur l'icône de l'AppStore.

  • PyrohPyroh Membre
    septembre 2017 modifié #13

    Comme Draken l'a dit c'est du Swift 4.0 donc Xcode 9 est requis.


    Pour Swift 3.1 ceci devrait compiler :



    let studentsByLevel = students.lazy.reduce([String: [Student]]()) { (acc, student) -> [String: [Student]] in
    var macc = acc
    if acc[student.level] != nil {
    macc[student.level]?.append(student)
    } else {
    macc[student.level] = [student]
    }
    return macc
    }.map { $0.value }

    print(studentsByLevel)

    Pour ce qui est du lazy je suis pas sur de son utilité avec reduce mais c'est à  vérifier et une chose est suÌ‚re c'est que ça ne mange pas de pain. 


Connectez-vous ou Inscrivez-vous pour répondre.