Partage
  • Partager sur Facebook
  • Partager sur Twitter

[VB.NET] Comparaison d'éléments dans une liste

Comparer deux éléments grâce à leur méthode ToString

Sujet résolu
    15 janvier 2019 à 11:03:48

    Bonjour,

    J'ai un petit problème pour comparer deux items dans une liste. En gros dans un fichier xml je récupère des objets Erreurs et j'ai modifié la méthode ToString de ces "Erreurs" pour éviter les doublons au moment de les ajouter dans une liste.

    For Each e As Erreur In valgrindOutput.Erreur
                If Not Me.LIST_ERREURS.Items.Contains(e.ToString) Then
                    Me.LIST_ERREURS.Items.Add(e)
                End If
            Next

    Le soucis c'est que même si l'item est déjà dans la liste il rentre dans mon If et ajoute la nouvelle erreur qui a pourtant le même nom...

     

    Je compare bien UninitCondition a UninitCondition pourtant ?

    Du coup j'obtiens la liste suivante :

    -
    Edité par BriceBoy 15 janvier 2019 à 11:06:29

    • Partager sur Facebook
    • Partager sur Twitter
      15 janvier 2019 à 11:46:56

      Salut,

      Tu pourrais nous montrer la déclaration de ta LIST_ERREURS ? Et ta méthode ToString ?

      Je me trompe peut-être mais je suppose que ta LIST_ERREURS contient des objets Erreur, et pas des strings, donc à moins que tu n'ais redéfini la méthode Contains, la condition de ton IF test si t'as liste contient un objet String et non pas un objet Erreur. C'est donc logique que cela renvoie "FALSE".

      En esperant t'avoir aidé,

      • Partager sur Facebook
      • Partager sur Twitter
        15 janvier 2019 à 13:20:05

        Merci de ton aide earp91, je commence à cerner le problème ^^

        Pour toi il faudrait que je donc que je redéfinisse la méthode Contains, mais dans quelle classe ?

        En effet si tu regardes la ligne ou j'ajoute les éléments dans la liste ils sont de type erreur : 

        For Each e As Erreur In valgrindOutput.Erreur
                    If Not Me.LIST_ERREURS.Items.Contains(e.ToString) Then
                        Me.LIST_ERREURS.Items.Add(e)
                    End If
        Next

        La classe est erreur est définie comme ça :

            <XmlRoot(ElementName:="error")>
            Public Class Erreur
                <XmlElement(ElementName:="unique")>
                Public Unique As String
                <XmlElement(ElementName:="tid")>
                Public Tid As String
                <XmlElement(ElementName:="kind")>
                Public Kind As String
                <XmlElement(ElementName:="what")>
                Public What As String
                <XmlElement(ElementName:="stack")>
                Public Stack As List(Of Stack)
                <XmlElement(ElementName:="auxwhat")>
                Public Auxwhat As String
            <XmlElement(ElementName:="xwhat")>
            Public Xwhat As Xwhat
        
            Public Overrides Function ToString() As String
                Return Kind
            End Function
        End Class

        En gros je redéfinis ToString pour qu'il retourne Kind car c'est à ça que je peux voir que deux erreurs sont identiques


        • Partager sur Facebook
        • Partager sur Twitter
          15 janvier 2019 à 14:15:53

          En fait d'après ce que j'ai vu le .Contains s'appuie sur la méthode Equals() de IEquatable pour déterminer si ton objet est présent dans la liste ou non.

          Tu dois donc implémenter IEquatable<Erreur> et redéfinir la méthode Equals() et faire un truc du genre :

          public class Erreur : IEquatable<Erreur>{
              public Erreur()
              {
                  //Construct
              }
              public bool Equals(Erreur e)
              {
                  return this.kind==e.kind;
              }
          }
          
          • Partager sur Facebook
          • Partager sur Twitter
            15 janvier 2019 à 14:25:51

            J'ai déjà essayé de redéfinir Equals, malheureusement ça ne s'est pas avéré très fructueux. Après je n'avais pas implémenté l'interface le problème était peut être là...

            Pour mon traitement finalement je me suis rendu compte que j'aurais sûrement besoin de Listes de Listes donc j'ai pas mal modifié cette partie du programme mais j'ai opté pour la solution facile pour ne pas ajouter en double les erreurs c'est à dire, créer une Liste de string qui sert à stocker les noms des erreurs (e.Kind). Une fois cela fait le test est très simple... Maintenant je vais juste bien galérer à utiliser mes listes de listes ^^

            Le code maintenant est le suivant : 

                    Dim ListeDeNoms As New List(Of String)
                    Dim ListeGlobale As New List(Of List(Of Erreur))
            
                    For Each e As Erreur In valgrindOutput.Erreur
                        If Not ListeDeNoms.Contains(e.Kind) Then
                            ListeDeNoms.Add(e.Kind)
                        End If
                    Next
            
                    For Each n As String In ListeDeNoms
                        Dim ListeErreurs As New List(Of Erreur)
                        For Each e As Erreur In valgrindOutput.Erreur
                            If e.Kind = n Then
                                ListeErreurs.Add(e)
                            End If
                        Next
                        ListeGlobale.Add(ListeErreurs)
                    Next
            
                    For Each liste As List(Of Erreur) In ListeGlobale
                        Me.LIST_ERREURS.Items.Add(liste)
                    Next

            En tous cas je te remercie de ton implication earp91 c'est vraiment cool ^^

            -
            Edité par BriceBoy 15 janvier 2019 à 14:49:39

            • Partager sur Facebook
            • Partager sur Twitter
              15 janvier 2019 à 16:18:30

              Oui je te confirme que si tu n'as pas implémenter l'interface ca ne peut pas marcher.

              C'est pas très beau toutes ces listes :P. .

              Je ne sais pas ce que tu veux essayer de faire mais j'ai l'impression que tu veux aller au sud mais que tu insistes pour faire un détour par le nord (j'ai pas su trouver une meilleur image desolé )

              Si tu veux pas t'embeter avec IEquatable, utilise au moins un Dictionary<Key,Value> ca sera bien plus adapté.

              Au cas où tu ne connaisses pas le principe : https://www.dotnetperls.com/dictionary-vbnet

              Avec ca, tu pourras utiliser ton attribut kind comme clé et ton objet Erreur comme valeur. Ainsi, quand tu voudras ajouter des élements a ta liste sans qu'il n'y ai de doublon, tu auras juste a vérifier que ton dictionnaire ne contient pas la clé de ton objet courant, comme ca :

              Dictionary<String, Erreur> mesErreurs = New Dictionary<String, Erreur>();
              
              foreach(Erreur e in valGrindOutput.Erreur)
              {
                  if (!mesErreurs.ContainsKey(e.Kind))
                  {
                      mesErreurs.Add(e.Kind,e);
                  }
              }
              

              C'est quand même plus court :)

              Desolé pour les explications un peu approximatives, je suis pas un pro

              Avec plaisir ;)

              • Partager sur Facebook
              • Partager sur Twitter
                16 janvier 2019 à 16:04:03

                En fait ma liste de liste me permet de regrouper les erreurs grâce au kind sans faire disparaître les "doublons" car je dois garder les details pour chacune. Du coup j'utilise un treeview pour les afficher avec une arborescence comme par exemple ici : 

                En gros toutes les erreurs avec le même attribut kind sont regroupées et ensuite elles sont listées grâce leur attribut unique qui comme son nom l'indique est unique (une sorte d'ID). Du coup vu que dans un TreeView ce ne sont que des string enregistrés et que je ne peux pas utiliser mes erreurs directement, j'ajoute chaque erreur dans ma listebox (cachée) et lorsque je sélectionne une erreur dans mon TreeView je cherche l'élément ayant le même "unique" dans ma liste pour le traitement qui s'en suit :p

                Le code maintenant que c'est un bordel sans nom :

                    Private Sub DeserialisationValgrind()
                        Me.TV_ERREURS_VALGRIND.Visible = True
                        Me.LIST_ERREURS.Visible = False
                        Dim Reader As Stream = File.OpenRead(Me.TXT_PATH_OUVR.Text)
                        Dim Deserialiseur As New XmlSerializer(GetType(Valgrindoutput))
                        Dim valgrindOutput As Valgrindoutput = Deserialiseur.Deserialize(Reader)
                
                        Dim ListeDeNoms As New List(Of String)
                        Dim ListeGlobale As New List(Of List(Of Erreur))
                
                        For Each e As Erreur In valgrindOutput.Erreur
                            Me.LIST_ERREURS.Items.Add(e)
                            If Not ListeDeNoms.Contains(e.Kind) Then
                                ListeDeNoms.Add(e.Kind)
                            End If
                        Next
                
                        For Each n As String In ListeDeNoms
                            Dim ListeErreurs As New List(Of Erreur)
                            For Each e As Erreur In valgrindOutput.Erreur
                                If e.Kind = n Then
                                    ListeErreurs.Add(e)
                                End If
                            Next
                            ListeGlobale.Add(ListeErreurs)
                        Next
                
                        Dim Compt As Integer = 0
                
                        For Each liste As List(Of Erreur) In ListeGlobale
                            Dim Occurrences As String
                            If liste.Count > 1 Then
                                Occurrences = " occurrences"
                            Else
                                Occurrences = " occurence"
                            End If
                            Me.TV_ERREURS_VALGRIND.Nodes.Add(liste(0).Kind & " : " & liste.Count & Occurrences)
                            Me.TV_ERREURS_VALGRIND.SelectedNode = Me.TV_ERREURS_VALGRIND.Nodes.Item(Compt)
                            For Each e As Erreur In liste
                                Me.TV_ERREURS_VALGRIND.SelectedNode.Nodes.Add(e.Unique)
                            Next
                            Compt += 1
                        Next
                
                        Reader.Close()
                        AffichageNbErreurs()
                    End Sub


                Ça fait beaucoup de boucles For Each,c'est sûrement pas optimisé... mais fonctionnel ^^

                -
                Edité par BriceBoy 16 janvier 2019 à 16:07:08

                • Partager sur Facebook
                • Partager sur Twitter
                  16 janvier 2019 à 19:26:26

                  L'histoire d'avoir les erreurs groupées par «kind» ça devrait pouvoir se faire plus facilement avec un groupby ou un tolookup (linq) ; enfin j'ai survolé le sujet vite fait, j'ai peut-être loupé un truc
                  • Partager sur Facebook
                  • Partager sur Twitter
                  Censément, quelqu'un de sensé est censé s'exprimer sensément.
                    17 janvier 2019 à 15:32:58

                    Pas bête j'avoue que je n'avais jamais entendu parler de GroupBy je me renseignerais, je te remercie Sehnsucht ;)
                    • Partager sur Facebook
                    • Partager sur Twitter

                    [VB.NET] Comparaison d'éléments dans une liste

                    × 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