trier un tableau composé de 3 NSNumber

Bonjour à  tous 


 


J'ai un tableau composé d'un tableau de 3 NSNumber, de la façon suivante : 



NSMutableArray *tableauPrincipal = [[NSMutableArray alloc]init];

NSNumber *V1 = [NSNumber numberWithInt:1];
NSNumber *V2 = [NSNumber numberWithInt:5];
NSNumber *V3 = [NSNumber numberWithInt:0];

NSMutableArray *arrayDeNumber = [NSMutableArray arrayWithContentsOfURL:V1,V2,V3,nil];

[tableauPrincipal addObject: arrayDeNumber];
.....

A titre d'exemple, voici en ordre de saisie ce que j'ai : 


 


V1 V2 V3


1   5    0


3   7    5


2   3    6


0   5    8


 


et je voudrais après le tri sur V1: 


V1 V2 V3


0   5    8


1   5    0


2   3    6


3   7    5


 


Je voudrais donc connaitre la solution la plus simple .... sans avoir à  créer un objet spécifique pour ça!!!


 


Merci d'avance


 


 


 

«1

Réponses

  • LarmeLarme Membre
    avril 2017 modifié #2

    J'avouerai que je ne suis pas sûr d'avoir saisi toute la logique.


     


    Si tu souhaites trier un NSMutableArray, tu peux juste appeler une des nombreuses méthodes (en fonction de ton tri) sortUsing...: de NSMutableArray


  • oui bien sûr mais je ne veux trier que par rapport à  V1


  • LarmeLarme Membre
    avril 2017 modifié #4

    Je suis un peu perdu, parce que j'ai dû mal à  trouver la relation entre ton code et le "schéma". (surtout que j'ai un arrayWithContentsOfURL: qui fait je ne sais quoi ici).


    Quand tu dis ne vouloir trier que par rapport à  V1, là , ça me met sur la piste que ton modèle est peut-être erroné. En tout cas, c'est pas clair. J'aurais besoin d'un véritable exemple de code et du résultat final souhaité.


  • Ah oui


    Non c'est une erreur de ma part, il s'agit de         


     


    NSMutableArray *arrayDeNumber = [NSMutableArray arrayWithObjects:V1,V2,V3,nil];


     


    Donc voici le code




    NSMutableArray *tableauPrincipal = [[NSMutableArray alloc]init];

    for (int i=0; i<10; i++)
    {
    NSNumber *V1 = [NSNumber numberWithInt:(rand()%100)+1];
    NSNumber *V2 = [NSNumber numberWithInt:(rand()%100)+1];
    NSNumber *V3 = [NSNumber numberWithInt:(rand()%100)+1];

    NSMutableArray *arrayDeNumber = [NSMutableArray arrayWithObjects:V1,V2,V3,nil];

    [tableauPrincipal addObject: arrayDeNumber];


        Ce que je veux, c'est que tableauPrincipal[0] ai la plus petite valeur de V1 et que tableauPrincipal[9] ai la plus grande valeur de V1 sachant que V2 et V3 doivent correspondre à  V1 (revoir l'exemple de ci dessus)
  • Je verrai deux solutions:


    1/ La plus simple


    Une classe V dont les champs serait V1, V2, V3, ... . Pour le tri il suffit ensuite d'utiliser les méthodes de tri de NSArray (sortusing...) comme l'a indiquer Larme.


    2/ Solution "un peu plus complexe mais après tout cela dépend des besoins"


    Avoir un NSNumber V qui serait la concaténation de V1*1000000 + V2 * 1000 + V3. V1, V2 et V3 serait limité de 0 à  999 (sinon cela ne fonctionne pas). Pour le tri il faut aussi utiliser les fonctions de tri de NSArray (encore)


  • Ok mais pour le sort using : j'ai essayé ça mais ça plante : 



    NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@self ascending:YES] autorelease];
    NSArray *sort = [NSArray arrayWithObject:sortDescriptor];

    [tableauPrincipal sortUsingDescriptors:sort];
  • Vite fait:



    NSMutableArray *tableauPrincipal = [[NSMutableArray alloc]init];
       
        for (int i = 0; i < 10; i++)
        {
            NSNumber *v1 = [NSNumber numberWithInt:(rand()%100)+1];
            NSNumber *v2 = [NSNumber numberWithInt:(rand()%100)+1];
            NSNumber *v3 = [NSNumber numberWithInt:(rand()%100)+1];
           
            NSMutableArray *arrayDeNumber = [NSMutableArray arrayWithObjects:v1,v2,v3,nil];
            [tableauPrincipal addObject: arrayDeNumber];
        }
        NSLog(@Tableau Principal: %@", tableauPrincipal);
       
        [tableauPrincipal sortUsingComparator:^NSComparisonResult(NSMutableArray * _Nonnull obj1, NSMutableArray * _Nonnull obj2) {
            NSComparisonResult result;
            for (NSUInteger i = 0; i < 3; i ++)
            {
                result = [obj1[i] compare:obj2[i]];
                if (result != NSOrderedSame)
                {
                    return result;
                }
            }
            return NSOrderedSame;
        }];
       
        NSLog(@Tableau Principal Sorted: %@", tableauPrincipal);
  • GENIAL....


    Merci à  toi Larme


     


    Mais dis moi, comment la fonction sait qu'il s'agit de trier sur V1 et pas sur les autres, du coup, si je voulais faire un tri sur V2 cette fois ci???


     


    Merci d'avance


  • LarmeLarme Membre
    avril 2017 modifié #10

    Explication du block:



    ​NSComparisonResult result;
    for (NSUInteger i = 0; i < 3; i ++)
    {
    result = [obj1[i] compare:obj2[i]];
    if (result != NSOrderedSame)
    {
    return result;
    }
    }
    return NSOrderedSame;

    Tu compares tes arrays un à  un (obj1 et obj2)


    La for loop sert à  comparer les sous-éléments (NSNumber) du même index entre obj1 et obj2.


    Si ils ne sont pas égaux, alors ça trie selon ce critère.


    Sinon, on compare les deux suivants. S'ils ne sont pas égaux, alors on trie selon ce critère.


    Sinon, on compare les deux suivants, etc.


    S'ils sont tous égaux, on renverra OrderedSame.


     


    Donc tel quel, on va comparer v1 et v1' et trier si possible, sinon v2 et v2' et trier si possible, puis v3' et v3'.


     


    J'ai fait ça car j'ai supposé que c'était ce que tu voulais.


     


     


     


    Si tu veux uniquement comparer sur v1 (qui est le premier élément sans te soucier des valeurs de v2 et v3), dans le block, tu écris uniquement :



    return [obj1[0] compare:obj2[0]];

    En décomposant, cela revient à  :



    NSNumber *v11 = obj1[0];
    NSNumber *v12 = obj2[0];
    return [v11 compare:v12];

    Si tu veux comparer uniquement sur v2 :



    return [obj1[1] compare:obj2[1]];

  • Joanna CarterJoanna Carter Membre, Modérateur
    avril 2017 modifié #11

    Pareil que Larme mais avec les petits trucs de code :



    NSMutableArray *tableauPrincipal = [NSMutableArray array];

    for (int i=0; i < 10; i++)
    {
    NSNumber *V1 = [NSNumber numberWithInt:(rand()%100)+1];

    NSNumber *V2 = [NSNumber numberWithInt:(rand()%100)+1];

    NSNumber *V3 = [NSNumber numberWithInt:(rand()%100)+1];

    NSArray *arrayDeNumber = @[;V1,V2,V3];

    [tableauPrincipal addObject: arrayDeNumber];
    }

    [tableauPrincipal sortUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2)
    {
    return [obj1[0] compare:obj2[0]];
    }];

    NSLog(@%@", tableauPrincipal); 

    (Je l'ai fait au même temps que Larme et je ne voulais pas le gaspiller  ::) )


  • Pourquoi tu passes par integerValue et en déduis toi-même un NSOrderedZzZ alors que NSNumber le fait très bien tout seul ?

  • Encore un énormes merci à  tous pour ces renseignements


  • Joanna CarterJoanna Carter Membre, Modérateur


    Pourquoi tu passes par integerValue et en déduis toi-même un NSOrderedZzZ alors que NSNumber le fait très bien tout seul ?




     


     


     


    Paah !! Tu l'as vu avant que je l'ai édité  ::)

  • MickMick Membre
    mai 2017 modifié #15

    Bonjour,


     


    au niveau du modèle, ce ne serait pas plus simple de faire un NSArray de dictionnaires ? Il y a alors un NSArray, et le tri se fait tout seul avec les NSSortDescriptors, non ?Il semble que tu veuilles que ces 3 valeurs soit "un objet", et pas 3 objets indépendants ? Le tableau contient ainsi des triplets de nombres, ce qui évite 3 tableaux différents, à  gérer simultanément. Mais après je ne sais pas ce que tu en fais, donc e suis peut-être à  coté de la plaque sur tes besoins.



    NSMutableArray *donnees=[[NSMutableArray alloc] init];
            for (int i=0; i<3; i++) {
                NSNumber *V1=[NSNumber numberWithInt:rand()%10+1];
                NSNumber *V2=[NSNumber numberWithInt:rand()%10+1];
                NSNumber *V3=[NSNumber numberWithInt:rand()%10+1];
                NSMutableDictionary *uneDonneeCEst3Nombres=[NSMutableDictionary dictionaryWithObjectsAndKeys:V1,@V1,V2,@V2,V3,@V3, nil];
                [donnees addObject:uneDonneeCEst3Nombres];
            }
            NSLog(@Tri par V1 croissant : %@",[donnees sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@V1 ascending:YES]]]);
            
            NSLog(@Tri par V2 croissant : %@",[donnees sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@V2 ascending:YES]]]);
            
            NSLog(@Tri par V3 croissant : %@",[donnees sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@V3 ascending:YES]]]);
     

  • Bonjour Mick


     


    C'est vrai que je n'avais pas pensé à  cette solution qui est assez simple au fond...Je ne pense jamais assez aux dictionnary


     


    Merci à  toi


  • Joanna CarterJoanna Carter Membre, Modérateur

    Les dictionnaires ne sont ni nécessaires ni triés


  • ...mais dans l'organisation de Mick, ça marche non ?


  • MickMick Membre

    Bonjour Joanna, je ne comprends pas ce que tu veux dire. Les dictionnaires ne sont pas triés, ce n'est pas leur vocation, ça on est d'accord. Je pense que Fred veut des triplets de nombres, pas des nombres indépendants. J'imagine par exemple que la première "colonne" du tableau correspond à  une "qualité" d'un objet plus grand, du genre la position "x" d'un point, la seconde la position "y" et la troisième la position "z" d'un même point. Mais je me trompe peut-être sur le but de la chose encore une fois. Et à  la place du dictionnaire, une sous-classe NSObject peut-être plus adaptée.


  • Joanna CarterJoanna Carter Membre, Modérateur

    J'ai déjà  montré le bon code avec les Arrays.


  • MickMick Membre

    Oui, ce n'est pas le problème, je suggérais juste de revoir peut-être l'organisation de la couche "données". Je ne remettais pas en cause les codes proposés ! 


  • LarmeLarme Membre


     


    Bonjour,


     


    au niveau du modèle, ce ne serait pas plus simple de faire un NSArray de dictionnaires ? Il y a alors un NSArray, et le tri se fait tout seul avec les NSSortDescriptors, non ?Il semble que tu veuilles que ces 3 valeurs soit "un objet", et pas 3 objets indépendants ? Le tableau contient ainsi des triplets de nombres, ce qui évite 3 tableaux différents, à  gérer simultanément. Mais après je ne sais pas ce que tu en fais, donc e suis peut-être à  coté de la plaque sur tes besoins.


     




     




    Quand tu dis ne vouloir trier que par rapport à  V1, là , ça me met sur la piste que ton modèle est peut-être erroné. En tout cas, c'est pas clair. J'aurais besoin d'un véritable exemple de code et du résultat final souhaité.




     




    Une classe V dont les champs serait V1, V2, V3, ... . Pour le tri il suffit ensuite d'utiliser les méthodes de tri de NSArray (sortusing...) comme l'a indiquer Larme.




    ;)

  • Bravo Mick... c'est exactement ce que je cherchais à  faire !!!!


  • MickMick Membre
    mai 2017 modifié #24

    Effectivement, Larme, cela avait déjà  été dit ! ... Mais la question était "sans créer un objet", "la solution la plus simple", c'est pour ça que j'ai évoqué les NSMutableDictionnary. 

  • Plus simple, plus lisible, plus beau, plus moderne, plus mieux et avec une meilleure haleine :


     



     


    Avant : 



    85 7 39


    43 14 71


    6 26 26


    90 63 34


    97 81 91


     


    Aprés : 



    6 26 26


    43 14 71


    85 7 39


    90 63 34


    97 81 91


     



    import UIKit

    typealias Triplet = (v1:Int, v2:Int, v3:Int)

    class ViewController: UIViewController {

    override func viewDidLoad() {
    super.viewDidLoad()

    let origine = randomTableau(taille: 5)
    print ("Avant : ")
    afficherTableau(origine)

    // $0.v2 < $1.v2 pour trier sur la valeur 2
    // $0.v3 < $1.v3 pour trier sur la valeur 3
    let tri = origine.sorted(by: { $0.v1 < $1.v1 } )
    print ()
    print ("Aprés : ")
    afficherTableau(tri)

    }

    func afficherTableau(_ tableau:[Triplet]) {
    print (" ")
    for t in tableau {
    print (t.v1, t.v2, t.v3)
    }
    }

    func randomTableau(taille:Int) -> [Triplet] {
    var tableau = [Triplet]()
    for _ in 1 ... taille {
    tableau.append(randomTriplet())
    }
    return tableau
    }

    func randomTriplet() -> Triplet {
    let t = Triplet(
    Int(arc4random_uniform(100)),
    Int(arc4random_uniform(100)),
    Int(arc4random_uniform(100))
    )
    return t
    }

    }

  • MickMick Membre
    mai 2017 modifié #26

    "Plus simple, plus lisible, plus beau, plus moderne" : tout à  fait d'accord, et j'en prends "de la graine"


    "avec une meilleure haleine" : tout dépend de ce que tu as consommé hier soir ....




  • "avec une meilleure haleine" : tout dépend de ce que tu as consommé hier soir ....




     


    Si t'as regardé les derniers épisodes de Game of Thrones, tu dois avoir une idée du menu draconien de base.

  • Joanna CarterJoanna Carter Membre, Modérateur

    @Draken - en utilisant les tuples, c'est bien mieux mais mon code était conçu sur le base d'un question de Fred20 en Objective-C ; sinon, j'aurais fait presque la même chose.


     


    @Fred20 - Qu'est-ce tu cherchais que la réponse de Mick t'a donné ?


  • MickMick Membre
    mai 2017 modifié #29

    @Joanna : je pense qu'il voulait dire que j'avais mis dans le mille  : en fait, les 3 nombres V1 V2 et V3 sont des coordonnées de quelque chose.


     


    Autre chose : je ne prétends absolument pas détenir les compétences que tu as en développement, et je cherche simplement a partager ma modeste expérience. J'ai cru apporter une autre réponse adaptée au problème de Fred, à  savoir une astuce simple qui ne nécessitait pas de créer une nouvelle classe pour trier des triplets de nombre au lieu de trier 3 tableaux simultanément. Je ne dis pas que c'est propre et que c'est la meilleure solution.


     


    Je crois déceler dans tes réponses un soupçon d'agacement, et j'en suis désolé, mais sache que je ne suis pas dans l'esprit de "concours de la meilleure solution", je le perdrais évidemment d'avance, n'étant pas développeur "pro"!


  • DrakenDraken Membre
    mai 2017 modifié #30


    @Draken - en utilisant les tuples, c'est bien mieux mais mon code était conçu sur le base d'un question de Fred20 en Objective-C ; sinon, j'aurais fait presque la même chose.




    Je me doute bien.


    Toi tu postes pour aider à  résoudre le problème de Fred20.


    Moi c'est pour faire de la propagande pro-Swift  >:D


  • Joanna CarterJoanna Carter Membre, Modérateur


    @Joanna : je pense qu'il voulait dire que j'avais mis dans le mille  : en fait, les 3 nombres V1 V2 et V3 sont des coordonnées de quelque chose.




     


    Du coup, pourquoi pas utiliser une petite struct ?



    typedef struct Point3D
    {
    CGFloat x, y, z;
    } Point3D;
Connectez-vous ou Inscrivez-vous pour répondre.