Partage
  • Partager sur Facebook
  • Partager sur Twitter

Vérifier que toute les valeur d'un array soient uniques

    23 mai 2011 à 14:56:44

    Salut,
    mon titre est explicite je pense, et vous l'aurez compris, je cherche à vérifier si mon array ou mon ArrayList ne contient pas deux fois la même valeur ...

    alors il y a plein de moyen, comme parcourir l'array en prenant chacune des valeur, puis en faisant une recherche sur l'array pour vérifier qu'il n'y a qu'une valeur ...
    Mais ce procédé me paraît horriblement lourd ...

    Et je ne voit pas trop comment faire d'autre ...
    vous auriez une idée ?
    Merci d'avance.
    • Partager sur Facebook
    • Partager sur Twitter
      23 mai 2011 à 14:58:28

      Salut.

      Pourquoi ne pas utiliser des Set plutôt qu'une arraylist. Un set est une collection où les éléments ne peuvent être présent deux fois. Il suffit de redefinir la méthode equals et hashcode pour être tranquille :)
      • Partager sur Facebook
      • Partager sur Twitter
        23 mai 2011 à 15:28:52

        Merveilleux merci beaucoup, c'était aussi dans l'espérance d'une telle réponse que j'ai posté ce topic ...
        Maintenant que j'y repense, je croit en effet que le tuto de Cysboy l'avait dit ...
        Mais je ne m’en rappelait plus ...
        Merci beaucoup, je regarde ça !

        EDIT

        Stop !
        Mon cas est plus spécial.
        Eh oui, ce HashSet est drôlement intéressant pour ça, mais là vois-tu, c'est à l'importation du fichier CSV ...
        donc voilà le résultat obtenu :

        {"col1", "col2", "col3"},{"item1", "item2", "item3"},{"item1", "item2", "item3"}

        etc. et ce sous forme d'arrayList ou de tableau ...
        Voilà, c'est là que ça se complique ...
        Je peux faire ça avec un arrayList de HashSet, ça ne pourra empêcher les doublons que sur les lignes ...
        comment faire donc pour faire ça sur les colonnes ...
        A moins de parcourir toutes les lignes en mettant l'item de la colonne en question dans un HashSet qui permet de vérifier l'unicité ... Mais c'est encore plutôt lourd ...
        qu'en penses-tu ?
        • Partager sur Facebook
        • Partager sur Twitter
          23 mai 2011 à 17:54:59

          Tu cherches un conteneur de ce type :
          {col1, col2, col3}
          {itm1, itm2, itm3}
          {itm1, itm2, itm3}

          ou chaque ligne est 'unique' ?
          • Partager sur Facebook
          • Partager sur Twitter
            23 mai 2011 à 18:01:20

            Presque, le conteneur est de ce genre.
            Le problème, c'est que je ne veux pas comme tu dis chaque ligne 'unique', mais bien une colonne ou chaque item est unique, comme dans le champs id d'une base de données si tu veux ...

            Donc ton exemple ne vas pas puisque que item1 se répète ... tu voit ce que je cherche à faire ?
            En fait, cette colonne extraite du .csv vas être mise en base de données ...
            Donc il faut que je vérifie que certaines colonnes soit "en primary key" ...
            En fait, la bdd me lèverai une exception ... Mais j'aimerai savoir avant si le fichier est juste, c'est pour ça ...
            • Partager sur Facebook
            • Partager sur Twitter
              23 mai 2011 à 18:38:38

              Si tu faire une correspondance avec une table, je te conseilles le pattern DAO. Ainsi plutôt que de stocker les infos comme tu le fait, tu pourra faire quelque chose du genre :
              {obj1}
              {obj2}
              {obj3}
              et chaque objet contient un attribut col1, col2 et col3.
              De cette manière, tu peux tout simplement définir la méthode equals de ton objet, qui permet de vérifier l'unicité de l'objet.
              Tu met le tout dans un Set, comme te l'a proposé maximus, et le tour est joué.
              EDIT: la méthode equals doit être cohérente avec la clé primaire de ta table. Il ne faut pas faire une comparaison de tous les champs de ta classe, mais juste sur les clés primaires (uniquement sur ID par exemple).
              • Partager sur Facebook
              • Partager sur Twitter
                24 mai 2011 à 9:29:25

                hum ... Je vois ...
                Le problème, c'est que ça ne vas pas être facile de récupérer les colonnes au lieu des lignes, à moins de parcourir toutes les lignes et stocké les résultat dans les colonnes ...
                Mais c'est faisable, même si c'est un peu lourd ...
                D'accord, je pense que je vais faire comme ça, je vais encore améliorer ma classe de lecture csv !
                a la fin, elle risque d'être pas mal ... Elle est pour le moment beaucoup plus rapide que la source que j'ai trouvé sur Développez qui marche mal ! (pas le droit du carac séparateur dans les cellules)
                Mais là, ça risque d'alourdir un peu, mais c'est pas grave, Java est tellement puissant :D
                Et l'utilisateur peu bien patienter 1 seconde quand même ! ;)
                Très bien, je vais faire comme ça, merci beaucoup.
                a+
                • Partager sur Facebook
                • Partager sur Twitter
                  24 mai 2011 à 9:36:31

                  Je ne sais pas quel est le fond du problème mais peut-être que dans le cadre de ton application il serait plus judicieux de faire en sorte que ce genre de cas soit impossible à obtenir en faisait la vérification AVANT insertion en base.
                  Parce que stocket quelqu'un chose de non valide ceymal. après peut-être que c'est uniquement dans un cas précis que c'est inutilisable auquel cas il faut continuer :)
                  • Partager sur Facebook
                  • Partager sur Twitter
                    24 mai 2011 à 9:44:15

                    Oui maximus, c'est pour ça que je voudrais vérifier avant, c'est mieux ...
                    • Partager sur Facebook
                    • Partager sur Twitter
                      24 mai 2011 à 9:45:27

                      J'ai pas compris ou était le problème de lecture avec ma méthode. Si ton csv est construit comme tu l'a écrit plus haut, alors il te suffit de lire dans l ordre et pour chaque {entité} tu crée un objet et tu lui affecte item1, item2 et item3.
                      • Partager sur Facebook
                      • Partager sur Twitter
                        24 mai 2011 à 9:56:24

                        Oui, mais en fait, là je traite ligne par ligne, et on ne peu pas faire autrement.
                        donc il faut que je modifie mon code en créant au début x colonnes sous forme d'ArrayList ou HashSet selon le cas (clé& primaire ou non).
                        ensuite, à chaque parcours de ligne, je mais l'Item dans sa bonne colonne.
                        Le problème, c'est que c'est un peu plus lourd (parce que sinon tu fait juste un split et l'array est fait !) ... et que ça m'oblige à modifier considérablement mon code (quelques centaines de lignes seulement :o ) ... ou plutôt à crée une option "clé primaire" ...
                        Mais bon, je vais le faire.

                        EDIT

                        en fait, c'est plus dur que ça, car il faut prévoir e cas ou une cellule contiendrait un carac séparateur, et là, ça fausserait tout ...
                        Je rentrerai pas dans les détails (csv est horriblement fastidieux), seulement, je suis donc obliger de traiter la ligne d'abord, puis de répartir les items dans les colonnes. le résultat est que c'est encore plus lourd, mais c'est la meilleure solution ;)
                        • Partager sur Facebook
                        • Partager sur Twitter
                          24 mai 2011 à 9:59:08

                          Euh, je n'ai pas trop compris tes explication :S
                          mais si mon approche perturbe grandement ta logique applicative, tu peux rester sur ton ancien modèle, y a d'autres solutions !
                          • Partager sur Facebook
                          • Partager sur Twitter
                            24 mai 2011 à 10:08:13

                            Non, mais c'est simplement que au lieu de vérifier les données après, je vais les vérifier pendant la lecture du fichier csv, ce qui évitera de faire double travail ...

                            En fait, le problème maintenant, c'est la lecture du csv, et c'est un tout autre problème ... qui serait beaucoup trop long à expliquer ... Mais le principe, c'est qu'au lieu qu'il y ai une liste (pou array ou HashSet) pour chaque ligne du fichier, il y ai une liste par colonne.

                            voilà, c'est simple en apparence :p
                            en fait, comme je l'ai dit, je suis obligé de traiter d'abord la ligne à cause des éventuels carac séparateurs, puis ensuite de transférer les éléments de la ligne dans sa colonne respective ...
                            Voilà, c'est simplement ça.
                            Après, tu devine la suite, pour ces listes, j'utilise un SetHash si je veux qu'une colonne soit "primary key", et le tour est joué ...
                            • Partager sur Facebook
                            • Partager sur Twitter
                              24 mai 2011 à 10:12:23

                              Je ne comprends vraiment pas pourquoi tu veux faire une liste par colonne.
                              Mon idée, c'était de faire UNE SEULE liste , ou chaque élément représente une ligne. Sachant que tu peut convertir chaque ligne en un objet, cela te fait une liste d'objet.
                              • Partager sur Facebook
                              • Partager sur Twitter
                                24 mai 2011 à 10:40:27

                                Ah oui, là en fait, le résultat c'est justement une seule liste avec dedans une liste ou plutôt un objet par ligne.
                                Le problème, c'est que comment veux-tu vérifier si une colonne ne contient pas deux fois la même valeur.
                                Oui, on pourrait faire comme ça puis faire un get pour récupérer chaque item de la colonne voulue, et mettre les résultats dans un HashSet pour vérifier l'unicité, mais c'est beaucoup plus lourd ...
                                Ou encore, faire un objet perso en redéfinissant la méthode toString, mais ça ne pourrait aller qu'avec une colonne ...
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  24 mai 2011 à 10:56:49

                                  Tu lis ton fichier ligne par ligne.

                                  A chaque ligne :
                                  -tu crée un objet perso.
                                  -tu lui ajoute tout les attributs que tu a trouver dans ta ligne (item1,item2,et item3).
                                  -tu met ce nouvel objet dans ta collection (liste, set, peu importe).

                                  A la fin de la lecture tu a donc toutes tes lignes représentées sous la forme d'un objet.

                                  Pour vérifier l'unicité de ses éléments, un Set utilise la méthode equals de ses éléments. Ainsi dans un Set tu ne peut pas avoir deux élément e1 et e2 tels que :
                                  e1.equals(e2) = true
                                  Par conséquent, si veut utiliser un Set tu va devoir redéfinir la méthode equals de ta classe perso.

                                  Au final tu aura quelque chose sous la forme :


                                  HashSet<monObjet> set = new HashSet<monObjet>();
                                  monObet tmp;
                                  //lecture du fichier
                                  //la boucle represente le traitement par ligne.
                                  while (nextLigne()){
                                       tmp = new mon Objet();
                                  
                                       //tu affecte les bonnes valeur a ton objet
                                       tmp.attribut1 = ligne.attribut1;
                                       tmp.attribut2 = ligne.attribut2;
                                       
                                       //et tu ajoute ton objet dans le set
                                       if(!set.add(monObjet){
                                            //si il était déjà présent, alors traitement de l'erreur.
                                            System.out.println("cette ligne est déjà présente.");
                                       }
                                  
                                  
                                  }
                                  


                                  La seule difficulté ici c'est de gérer le parse d'une ligne. Mais d'après ce que j'ai lu, tu a reussi à l'implémenter :)
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    24 mai 2011 à 11:12:16

                                    Ah oui ... je commence à comprendre ...
                                    Tu veux donc utiliser l'héritage et redéfinir la méthode, pas bête du tout ...
                                    D'accord, j'ai compris le principe, mais le tout est de savoir comment je vais redéfinir la méthode equals ...
                                    Ah oui, suis-je bête, il faut renvoyer la valeur de la colonne en question !
                                    Vraiment, tu es génial, je n'aurais jamais pensé à utiliser la puissance de l'héritage ...

                                    en fait, je n'y suis pas encore habitué, je n'aurais pas du apprendre le PHP, parce que j'ai gardé les principes PHP qui ne sont pas du tout POO ...

                                    Bon, un seul inconvénients, c'est si je veux que plusieurs colonnes soit en "clé unique" !
                                    Voilà qui complique un peu les choses ...

                                    En ce cas, il faudrait redéfinir la méthode add de HashSet !
                                    c'est le même principe ... mais pour redéfinir cette méthode ...
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      24 mai 2011 à 11:24:10

                                      Citation : Dominique0796

                                      Vraiment, tu es génial, je n'aurais jamais pensé à utiliser la puissance de l'héritage ...


                                      *sifflote* :soleil:
                                      Tu n'as même pas besoin de redéfinir add(). Il suffit de bien redéfinir la méthode equals. La tout dépend de l'organisation de tes données.
                                      C'est à toi de bien définir ce que tu entends par : deux lignes égales. Tous les champs doivent ils être égaux, ou seulement quelques un ( clé primaire par exemple) ?
                                      ta méthode equals doit être de ce genre :

                                      public boolean equals(Object o){
                                      MonObjet that = (MonObjet) o;
                                      
                                      //ici c'est toi qui choisit sur quel champs tu teste l'égalité, par exemple :
                                      if (this.ID == that.ID)
                                          return true;
                                      else 
                                          return false;
                                      }
                                      


                                      Mais tu peux avoir quelque chose de plus 'complexe', par exemple :

                                      public boolean equals(Object o){
                                      MonObjet that = (MonObjet) o;
                                      
                                      //ici c'est toi qui choisit sur quel champs tu teste l'égalité, par exemple :
                                      if (this.nom.equals(that.nom) && this.prenom.equals(that.prenom)))
                                          return true;
                                      else 
                                          return false;
                                      }
                                      

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        24 mai 2011 à 11:33:37

                                        Ah oui, tout simplement ...
                                        oui, c'est bête, je devrais me passer la tête à l'eau fraiche quelquefois :p
                                        Je me rappelait plus que dans un equals, on passe en paramètre l'autre objet à comparer ... :o:-°
                                        Merci, le dernier pb (dernier des dernier :p ), c'est que je voudrais que ma classe soit automatique, et que je n'ai pas à redéfinir l'objet à chaque fois ...

                                        Donc je sais ce que je vais faire, je passe l'array contenant l'index des colonnes qui doivent être unique, et ma classe principale stocke ça dans une variable ...
                                        ensuite, l'objet en question sera une sous-classe qui utilisera donc l'array contenant l'index des col en question ...

                                        Ok, tout y es, je vais m'y mettre !
                                        Et merci encore, je n'y aurais pas pensé seul ...

                                        EDIT

                                        Voilà donc ma classe :

                                        private class primareKey{
                                        	ArrayList<String> ar = new ArrayList<String>();
                                        	primareKey p;
                                        	int error = 0;
                                        	
                                        	public void add(String text){
                                        	   ar.add(text);
                                        	}
                                        	
                                        	public primareKey(){
                                        		
                                        	}
                                        	public String get(int index){
                                        		return ar.get(index);
                                        	}
                                        	public boolean equals(Object o){
                                        		error = 0;
                                        		p = (primareKey)o;
                                        		for(int i: except){
                                        			if(ar.get(i).equals(p.get(i))){
                                        				error++;
                                        			}
                                        		}
                                        		if(error==0)
                                        			return true;
                                        		else
                                        			return false;
                                        	}
                                        }
                                        


                                        A savoir que except est un int[] contenant l'index des colonne en "clé primaire" .

                                        ça devrait aller, il ne me reste plus qu'à l'adapter ici ...

                                        Mais dit moi, même si c'est un peu hors sujet, je voudrais que mon objet ce comporte comme un tableau quand on le parcours avec la boucle for simple ( ex: for(String t: text){ } )...

                                        quel méthode faut-il redéfinir ? ça doit être un truc avec next() sans doute ...
                                        Sinon, c'est pas trop grave, je ferais avec la boucle for traditionnelle avec un get à l'intérieur ...

                                        Aïe ... la méthode equals n'est pas appelée !!
                                        voici le code :
                                        if(!hs.add(castInPrimareKey(getLineAsArrayList(ligne)))){
                                        			System.out.println("Fichier incorrect !");
                                        			return null;
                                        		}
                                        


                                        J'ai mis un system.out.println dans la méthode equals pour voir si elle est appelée, elle ne l'est pas !

                                        A savoir, castInPrimareKey(getLineAsArrayList(ligne)) renvoie un objet primareKey ...

                                        bon, le problème vient du hashCode ...
                                        voir ce topic : http://www.siteduzero.com/forum-83-650 [...] edefinir.html

                                        En fait, la méthode equals n'est appelée que si il y a plusieurs index renvoyés par hashcode identiques !
                                        donc si tu ne renvoie jamais le même hashcode, equals n'est pas appelé !
                                        Seul remède, renvoyé toujours le même hashcode pour vérifier avec equals à chaque insertion ...

                                        Mais es-ce que ça peu nuire de renvoyer toujours le même hashcode ?!
                                        • Partager sur Facebook
                                        • Partager sur Twitter

                                        Vérifier que toute les valeur d'un array soient uniques

                                        × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                        × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                        • Editeur
                                        • Markdown