Indexer une liste structurée

Informations pour bien débuter en PureBasic
Avatar de l’utilisateur
microdevweb
Messages : 1800
Inscription : mer. 29/juin/2011 14:11
Localisation : Belgique

Indexer une liste structurée

Message par microdevweb »

La fonction sort Pb ne fonctionne que sur une seule donnée de la structure, trié une liste avec une grosse structure pourrait prendre du temps.

Voici une petit exemple avec une liste d'index (clé composée) liée à la liste, en gros on ne trie pas la liste principal mais uniquement la liste indexée, quand on ajoute un record on ajoute la clé à l'index par insertion triée.

Désolé mais le code à un peux été fait à l'arrache , je le replacerais au propre quand j'aurais le temps.

Voici la liste des fonction pour la gestion des index
  • StringCompare(FistChaine.s,TwoChaine.s) -> Compare deux chaines de caractère retourne -1 si la chaîne est plus petite 1 si plus grande 0 équivalente
  • IndexSort() ->Création de la liste d'index d'index
  • AddToIndex(Key.s,*Pos) -> inséré un nouvelle index (conserve le tri)
  • Looking(chaine.s) -> Recherche un élément si trouvé (même si la chaîne comparée est plus petite mais correspond) pointe sur la structure principale

Code : Tout sélectionner

Structure People
  Name.s
  FirstName.s
  Adress.s
  ZipCode.s
  Cyti.s
  Telephone.s
  Celular.s
EndStructure
Structure Index
  *Position
  Key.s
EndStructure
Global NewList myPeople.People()
Global NewList myIndex.Index()
Declare StringCompare(FistChaine.s,TwoChaine.s)
Declare AddData()
Declare IndexSort()
Declare DisplayIndex()
Declare Looking(chaine.s)
Declare AddToIndex(Key.s,*Pos)
Procedure StringCompare(FistChaine.s,TwoChaine.s)
  Protected i,max
  max=Len(FistChaine)
  
  For i=i To max
    If Asc(Mid(FistChaine,i,1))>Asc(Mid(TwoChaine,i,1))
      ProcedureReturn 1
    Else
      If Asc(Mid(FistChaine,i,1))<Asc(Mid(TwoChaine,i,1))
        ProcedureReturn  -1
      EndIf
    EndIf
  Next
  ProcedureReturn 0
EndProcedure
Procedure AddData()
  With myPeople()
    AddElement(myPeople())
    \Name="Zoala"
    \FirstName="Alain"
    AddElement(myPeople())
    \Name="Yatola"
    \FirstName="Halonin"
    AddElement(myPeople())
    \Name="Albinos"
    \FirstName="Bernard"
    AddElement(myPeople())
    \Name="Catorin"
    \FirstName="Brunot"
    AddElement(myPeople())
    \Name="Albinos"
    \FirstName="Pierre"
  EndWith
EndProcedure
Procedure IndexSort()
  Protected i,comp
  ClearList(myIndex())
  ForEach myPeople()
    With myIndex()
      If ListSize(myIndex())=0
        AddElement(myIndex())
      Else
        i=0
        ForEach myIndex()
          i+1
          comp=StringCompare(myPeople()\Name+" "+myPeople()\FirstName,\Key)
          If comp<0
            InsertElement(myIndex())
            Break
          Else
            If i=ListSize(myIndex())
              AddElement(myIndex())
            EndIf
          EndIf
        Next
      EndIf
      \Key=myPeople()\Name+" "+myPeople()\FirstName
      \Position=@myPeople()
    EndWith
  Next
EndProcedure
Procedure DisplayIndex()
  ForEach myIndex()
    With myIndex()
      Debug \Key
    EndWith
  Next
EndProcedure
Procedure Looking(chaine.s)
  Protected *adress=-1
  With myIndex()
    ForEach myIndex()
      If StringCompare(chaine,\Key)=0
        *adress=\Position
        Break
      EndIf
    Next
  EndWith
  If *adress>-1
    With myPeople()
      ChangeCurrentElement(myPeople(),*adress)
      Debug ""
      Debug "Element finding"
      Debug \Name+" "+\FirstName
    EndWith
  EndIf
EndProcedure
Procedure AddToIndex(Key.s,*Pos)
  With myIndex()
    If ListSize(myIndex())=0
      AddElement(myIndex())
    Else
      i=0
      ForEach myIndex()
        i+1
        comp=StringCompare(Key,\Key)
        If comp<0
          InsertElement(myIndex())
          Break
        Else
          If i=ListSize(myIndex())
            AddElement(myIndex())
          EndIf
        EndIf
      Next
    EndIf
    \Key=Key
    \Position=*Pos
  EndWith 
EndProcedure
AddData()
IndexSort()
Debug "Index list"
DisplayIndex()
Looking("Yato")

; Ici j'ajoute un élément
With myPeople()
  AddElement(myPeople())
  \Name="Gradon"
  \FirstName="Gérard"
  AddToIndex(\Name+" "+\FirstName,@myPeople())
EndWith
; J" affiche l'index pour vérifié
Debug "Index list"
DisplayIndex()

; Ici j'ajoute un élément
With myPeople()
  AddElement(myPeople())
  \Name="Gradon"
  \FirstName="Alan"
  AddToIndex(\Name+" "+\FirstName,@myPeople())
EndWith
; J' affiche l'index pour vérifié
Debug "Index list"
DisplayIndex()

Windows 10 64 bits PB: 5.70 ; 5.72 LST
Work at Centre Spatial de Liège
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Indexer une liste structurée

Message par falsam »

Ça me semble compliqué cette technique.

Pour de très grosses listes je passerais plutôt par un tri base de données en mémoire ou pas. Mais ce n'est pas le sujet.

Reste deux solutions :
- La clé dans la structure avec un tri final sur la clé.
- L'algorithme de tri fusion en natif dans PureBasic depuis la version 4.30.

Voyons voir ces deux cas avec un exemple

La clé dans la structure avec un tri final sur la clé.

Code : Tout sélectionner

Structure Test
  Clef.s
  
  Champs1.s
  Champs2.s
EndStructure

NewList Tableau.Test()

AddElement(Tableau())
With Tableau()
  \Champs1 = "Legumes"
  \Champs2 = "Tomates"
  \Clef = LSet(\Champs1, 30, " ") + LSet(\Champs2, 30, " ") 
EndWith

AddElement(Tableau())
With Tableau()
  \Champs1 = "Fruits"
  \Champs2 = "Oranges"
  \Clef = LSet(\Champs1, 30, " ") + LSet(\Champs2, 30, " ") 
EndWith

AddElement(Tableau())
With Tableau()
  \Champs1 = "Fruits"
  \Champs2 = "Abricots"
  \Clef = LSet(\Champs1, 30, " ") + LSet(\Champs2, 30, " ") 
EndWith

AddElement(Tableau())
With Tableau()
  \Champs1 = "Legumes"
  \Champs2 = "Pommes de terre"
  \Clef = LSet(\Champs1, 30, " ") + LSet(\Champs2, 30, " ") 
EndWith

SortStructuredList(Tableau(), #PB_Sort_Ascending, OffsetOf(Test\Clef), #PB_String)

ForEach Tableau()
  Debug Tableau()\Champs1 + " - " + Tableau()\Champs2
Next
L'algorithme de tri fusion en natif dans PureBasic depuis la version 4.30.

Code : Tout sélectionner

Structure Test
  Champs1.s
  Champs2.s
EndStructure

NewList Tableau.Test()

AddElement(Tableau())
With Tableau()
  \Champs1 = "Legumes"
  \Champs2 = "Tomates"
EndWith

AddElement(Tableau())
With Tableau()
  \Champs1 = "Fruits"
  \Champs2 = "Oranges"
EndWith

AddElement(Tableau())
With Tableau()
  \Champs1 = "Fruits"
  \Champs2 = "Abricots"
EndWith

AddElement(Tableau())
With Tableau()
  \Champs1 = "Legumes"
  \Champs2 = "Pommes de terre"
EndWith

SortStructuredList(Tableau(), #PB_Sort_Ascending, OffsetOf(Test\Champs1), #PB_String)
SortStructuredList(Tableau(), #PB_Sort_Ascending, OffsetOf(Test\Champs2), #PB_String)

ForEach Tableau()
  Debug Tableau()\Champs1 + " - " + Tableau()\Champs2
Next
Le résultat dans les deux cas est le même.
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
Micoute
Messages : 2522
Inscription : dim. 02/oct./2011 16:17
Localisation : 35520 La Mézière

Re: Indexer une liste structurée

Message par Micoute »

Plus facile à comprendre pour les novices :

Code : Tout sélectionner

Structure Test
 Categorie.s
 Nom.s
EndStructure

NewList Tableau.Test()

AddElement(Tableau())
With Tableau()
 \Categorie = "Legumes"
 \Nom = "Tomates"
EndWith

AddElement(Tableau())
With Tableau()
 \Categorie = "Fruits"
 \Nom = "Oranges"
EndWith

AddElement(Tableau())
With Tableau()
 \Categorie = "Fruits"
 \Nom = "Abricots"
EndWith

AddElement(Tableau())
With Tableau()
 \Categorie = "Legumes"
 \Nom = "Pommes de terre"
EndWith

SortStructuredList(Tableau(), #PB_Sort_Ascending, OffsetOf(Test\Categorie), #PB_String)
SortStructuredList(Tableau(), #PB_Sort_Ascending, OffsetOf(Test\Nom), #PB_String)

ForEach Tableau()
 Debug Tableau()\Categorie + " - " + Tableau()\Nom
Next
J'ai juste changé champs1 par categorie et champs2 par nom.
Merci falsam pour le partage
Microsoft Windows 10 Famille 64 bits : Carte mère : ASRock 970 Extreme3 R2.0 : Carte Graphique NVIDIA GeForce RTX 3080 : Processeur AMD FX 6300 6 cœurs 12 threads 3,50 GHz PB 5.73 PB 6.00 LTS (x64)
Un homme doit être poli, mais il doit aussi être libre !
Avatar de l’utilisateur
microdevweb
Messages : 1800
Inscription : mer. 29/juin/2011 14:11
Localisation : Belgique

Re: Indexer une liste structurée

Message par microdevweb »

Bonjour Falsam,

C'est juste le partage d'une technique (langage C) pour l'indexage qui est employé surtout pour par exemple une gestion de fichiers. Maintenant je ne sait pas comment fonctionne exactement en interne la function sort de Pb et la rapidité qui en résulte avec une grosse structure bien chargée.

Par contre je sais que Sql en mémoire fonctionne très bien.

Edit: (Je ferais peut être un petit exemple avec une gestion de fichier)
Windows 10 64 bits PB: 5.70 ; 5.72 LST
Work at Centre Spatial de Liège
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Indexer une liste structurée

Message par falsam »

je vais devoir faire un mea-culpa. Le tri fusion de List ne fonctionne pas avec PureBasic comme le montre ce contre exemple.

Code : Tout sélectionner

Structure Test
  Champs1.s
  Champs2.s
EndStructure

NewList Tableau.Test()

AddElement(Tableau())
With Tableau()
  \Champs1 = "Legumes"
  \Champs2 = "Tomates"
EndWith

AddElement(Tableau())
With Tableau()
  \Champs1 = "Fruits"
  \Champs2 = "Oranges"
EndWith

AddElement(Tableau())
With Tableau()
  \Champs1 = "Fruits"
  \Champs2 = "Abricots"
EndWith

AddElement(Tableau())
With Tableau()
  \Champs1 = "Legumes"
  \Champs2 = "Pommes de terre"
EndWith

AddElement(Tableau())
With Tableau()
  \Champs1 = "Fruits"
  \Champs2 = "Papaye"
EndWith

AddElement(Tableau())
With Tableau()
  \Champs1 = "Legumes"
  \Champs2 = "Courgettes"
EndWith

;Tri par famille et par produit
SortStructuredList(Tableau(), #PB_Sort_Ascending, OffsetOf(Test\Champs1), #PB_String)
SortStructuredList(Tableau(), #PB_Sort_Ascending, OffsetOf(Test\Champs2), #PB_String)

ForEach Tableau()
  Debug Tableau()\Champs1 + " - " + Tableau()\Champs2
Next
La méthode avec une clé dans la structure est la plus appropriée.

Code : Tout sélectionner

Structure Test
  Champs1.s
  Champs2.s
  Clef.s
EndStructure

NewList Tableau.Test()

AddElement(Tableau())
With Tableau()
  \Champs1 = "Legumes"
  \Champs2 = "Tomates"
EndWith

AddElement(Tableau())
With Tableau()
  \Champs1 = "Fruits"
  \Champs2 = "Oranges"
EndWith

AddElement(Tableau())
With Tableau()
  \Champs1 = "Fruits"
  \Champs2 = "Abricots"
EndWith

AddElement(Tableau())
With Tableau()
  \Champs1 = "Legumes"
  \Champs2 = "Pommes de terre"
EndWith

AddElement(Tableau())
With Tableau()
  \Champs1 = "Fruits"
  \Champs2 = "Papaye"
EndWith

AddElement(Tableau())
With Tableau()
  \Champs1 = "Legumes"
  \Champs2 = "Courgettes"
EndWith

;Creation des clés de tri
ForEach Tableau()
  With Tableau()
    \Clef = LSet(\Champs1, 30, " ") + LSet(\Champs2, 30, " ") 
  EndWith
Next

;Tri par famille et par produit
SortStructuredList(Tableau(), #PB_Sort_Ascending, OffsetOf(Test\Clef), #PB_String)

;Vérification
ForEach Tableau()
  Debug Tableau()\Champs1 + " - " + Tableau()\Champs2
Next
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Demivec
Messages : 90
Inscription : sam. 18/sept./2010 18:13

Re: Indexer une liste structurée

Message par Demivec »

falsam a écrit :je vais devoir faire un mea-culpa. Le tri fusion de List ne fonctionne pas avec PureBasic comme le montre ce contre exemple.
Utilisez ceci:

Code : Tout sélectionner

;Tri par famille et par produit
;(Trier la clé secondaire d'abord et la clé principale en dernier)
SortStructuredList(Tableau(), #PB_Sort_Ascending, OffsetOf(Test\Champs2), #PB_String)
SortStructuredList(Tableau(), #PB_Sort_Ascending, OffsetOf(Test\Champs1), #PB_String)
Répondre