Connaitre le nombre d'elements (sans doublons) d'un tableau

Résolu
nicobox2 Messages postés 23 Date d'inscription lundi 7 novembre 2005 Statut Membre Dernière intervention 14 décembre 2006 - 6 nov. 2006 à 19:09
 PCPT - 8 nov. 2006 à 00:38
Bonjour,

Y a t-il une fonction VB qui permet de connaitre le nombre d'élément d'un tableau mais sans les doublons ?

Ex de tableau :

toto
titi
toto
tutu

Nombre d'éléments : 3

Car là j'ai mal au crane et j'arrive plus à reflechir ...

D'avance merci bcp !

56 réponses

chaibat05 Messages postés 1883 Date d'inscription samedi 1 avril 2006 Statut Membre Dernière intervention 20 novembre 2007 2
7 nov. 2006 à 00:30
rectification
...
Do While (i<uB) And (sText=T(i+1))
      i=i+1
Loop
0
chaibat05 Messages postés 1883 Date d'inscription samedi 1 avril 2006 Statut Membre Dernière intervention 20 novembre 2007 2
7 nov. 2006 à 01:16
et effectivement je me suis perdu...
j'avais comme un présentiment...
'--------------------------------------------------------
Function Compte_Sans_Doublon() As integer
  Dim uB as integer
  uB= UBound(T)
  if uB=0 Then
     Compte_Sans_Doublon=0
  ElseIf uB=1 Then
     Compte_Sans_Doublon=1
  Else
     uB=uB-1
     Dim Temp() As String
     Dim i as Integr,  y As integer , sText As string
      y =0
    For i= 1 To uB
       y=y+1
       sText =T(i)
       Redim Preserve Temp(y)
       Temp(y)=sText
       Do While (i<uB) And (sText=T(i+1))
           i=i+1
       Loop
    Next
       Compte_Sans_Doublon=UBound(Temp)
   End If
End Function

'---------------------------------------------------

remarquez qu' à la place du Temp() on peut faire
 Dim sList As ListBox  ajouter las éléments avec sList.AddItem
 et récupérer sList.ListCount

PS:Pardon pour les posts successifs,
     mais ce sont les aleas du direct...
0
le cancre Messages postés 292 Date d'inscription mercredi 25 octobre 2006 Statut Membre Dernière intervention 27 novembre 2009
7 nov. 2006 à 01:50
salut chaibat ^^
lol
 ......il va etre content  nicobox2  avec tout ca
Pardon pour les posts successifs,
     mais ce sont les aleas du direct...
j'pense qu'on à tous le meme probleme

mais la maintenant, on à largement répondu j'pense
0
Gobillot Messages postés 3140 Date d'inscription vendredi 14 mai 2004 Statut Membre Dernière intervention 11 mars 2019 34
7 nov. 2006 à 01:51
une autre méthode plus rapide
les éléments sont comparés et triés au fur à mesure grace à un tableau d'index

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

Private Sub Form_Load()
    Dim Tableau(9) As String
    Dim element    As String
    Dim i          As Long
    Dim X()        As Long
    Dim P          As Long
    Dim G          As Long
    Dim M          As Long
    Dim Lb         As Long
    Dim Ub         As Long
    Dim nb         As Long

    Tableau(0) = "Valeur 1"
    Tableau(1) = "Valeur 5"
    Tableau(2) = "Valeur 1"
    Tableau(3) = "Valeur 3"
    Tableau(4) = "Valeur 6"
    Tableau(5) = "Valeur 4"
    Tableau(6) = "Valeur 5"
    Tableau(7) = "Valeur 4"
    Tableau(8) = "Valeur 7"
    Tableau(9) = "Valeur 2"
   
    Lb = LBound(Tableau)
    Ub = UBound(Tableau)    ReDim X(1): X(1) Lb: nb 1
   
    For i = Lb + 1 To Ub
        element = Tableau(i)        P 1: G nb
        While P < G
           M = (P + G) \ 2           If element > Tableau(X(M)) Then P M + 1 Else G M
           Wend
        If element <> Tableau(X(P)) Then
           If element > Tableau(X(P)) Then P = P + 1
           nb = nb + 1
           ReDim Preserve X(nb)
           If P < nb Then CopyMemory X(P + 1), X(P), (nb - P) * 4
           X(P) = i
           End If
        Next
    MsgBox "Compte sans Doublons=" & nb
End Sub

Daniel
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
le cancre Messages postés 292 Date d'inscription mercredi 25 octobre 2006 Statut Membre Dernière intervention 27 novembre 2009
7 nov. 2006 à 02:04
allez je relance le truc ......qui peut faire plus court?

Dim Compare As String, yo() As String
For i = 0 To UBound(TonTab)   If InStr(Compare, TonTab(i)) 0 Then Compare Compare & TonTab(i) & "/"
Next i
MsgBox "le nombre est  " & UBound(Split(Compare, "/"))
0
Gobillot Messages postés 3140 Date d'inscription vendredi 14 mai 2004 Statut Membre Dernière intervention 11 mars 2019 34
7 nov. 2006 à 02:19
plus court en longueur de code ou en temps:
le résultat est différent chercher l'erreur !!!!

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function GetTickCount Lib "kernel32" () As Long

Private Sub Form_Load()
    Dim Tableau()  As String
    Dim element    As String
    Dim i          As Long
    Dim X()        As Long
    Dim P          As Long
    Dim G          As Long
    Dim M          As Long
    Dim Lb         As Long
    Dim Ub         As Long
    Dim nb         As Long
    Dim Tps        As Long
    Dim Tp1        As Long
    Dim Tp2        As Long

    Randomize 1234
    ReDim Tableau(1 To 10000)
    Lb = LBound(Tableau)
    Ub = UBound(Tableau)    For i Lb To Ub: Tableau(i) Format$("0000", Rnd * 10000): Next
   
    Tps = GetTickCount    ReDim X(1): X(1) Lb: nb 1
    For i = Lb + 1 To Ub
        element = Tableau(i)        P 1: G nb
        While P < G
           M = (P + G) \ 2           If element > Tableau(X(M)) Then P M + 1 Else G M
           Wend
        If element <> Tableau(X(P)) Then
           If element > Tableau(X(P)) Then P = P + 1
           nb = nb + 1
           ReDim Preserve X(nb)
           If P < nb Then CopyMemory X(P + 1), X(P), (nb - P) * 4
           X(P) = i
           End If
        Next
    Tp1 = GetTickCount - Tps
    MsgBox "Temps nécessaire= " & Tp1
'   MsgBox "Compte sans Doublons=" & nb

    Dim Compare As String, yo() As String
    Tps = GetTickCount
    For i = Lb To Ub        If InStr(Compare, Tableau(i)) 0 Then Compare Compare & Tableau(i) & "/"
        Next
    nb = UBound(Split(Compare, "/"))
    Tp2 = GetTickCount - Tps
    MsgBox "Temps nécessaire= " & Tp2
'   MsgBox "le nombre est  " & nb
       
    MsgBox "rapport temps= " & Tp2 / Tp1
   
End Sub

Daniel
0
Gobillot Messages postés 3140 Date d'inscription vendredi 14 mai 2004 Statut Membre Dernière intervention 11 mars 2019 34
7 nov. 2006 à 02:36
la méthode par Collection donne le même nombre
mais je suis battu en Temps

    Dim cCollection  As New Collection
    Tps = GetTickCount
    On Error Resume Next
    For i = Lb To Ub
        cCollection.Add Tableau(i), Tableau(i)
        Next i
    nb = cCollection.Count
    Tp2 = GetTickCount - Tps
    MsgBox "Temps nécessaire= " & Tp2
    MsgBox "le nombre est  " & nb
   
    MsgBox "rapport temps= " & Tp1 / Tp2

Daniel
0
le cancre Messages postés 292 Date d'inscription mercredi 25 octobre 2006 Statut Membre Dernière intervention 27 novembre 2009
7 nov. 2006 à 02:50
oui je vois, mais là c'est en milliseconde ....ton code est plus rapide
apres aussi tout dépend du pc(processeur,ram)...etc
trop de ligne de code pour un simple truc j'trouve!
faut voir aussi niveau ressource
mais faut qu'on lache l'affaire ^^ ......apres c'est l'histoire sans fin
et de plus à chaque essai, j'ai jamais le meme temps!
apres on va finir par faire une démo avec du C++
0
Gobillot Messages postés 3140 Date d'inscription vendredi 14 mai 2004 Statut Membre Dernière intervention 11 mars 2019 34
7 nov. 2006 à 02:55
il est moins rapide que la collection (rapport entre 1 et 2)
par contre plus rapide que le tien (j'arrive à des rapports de 50)
en plus il y a une erreur:

ta comparaison par Instr() trouve des égalités où il n'y en pas vraiment

le morceau de chaîne peux être égal alors que la chaîne complète n'est pas la même

exemple :  /251/  et  /2510/  donne l'égalité ...

Daniel
0
le cancre Messages postés 292 Date d'inscription mercredi 25 octobre 2006 Statut Membre Dernière intervention 27 novembre 2009
7 nov. 2006 à 03:03
oui c'est du vite fait...j'ai pas pris mon temps ...et j'voulais pas le prendre...je corrige quand meme ma faute en gardant le meme principe

Dim Compare As String, yo() As String
For i = 0 To UBound(TonTab)
   If InStr(Compare, TonTab(i)) = 0 Then if len(Compare) len(TonTab(i)) then  Compare Compare & TonTab(i) & "/"
end if
Next i
MsgBox "le nombre est  " & UBound(Split(Compare, "/"))
0
Gobillot Messages postés 3140 Date d'inscription vendredi 14 mai 2004 Statut Membre Dernière intervention 11 mars 2019 34
7 nov. 2006 à 03:05
faut inclure les bornes, c'est la dire le "/" du début et de la fin
à condition qu'elles ne fassent par partie de la chaîne
voilà maintenant je trouve le même nombre:

    Dim Compare As String, yo() As String
    Compare = "/"
    For i = Lb To Ub
        If InStr(Compare, "/" & Tableau(i) & "/") = 0 Then
           Compare = Compare & Tableau(i) & "/"
           End If
        Next
    nb = UBound(Split(Compare, "/")) - 1
    MsgBox "le nombre est  " & nb

Daniel
0
le cancre Messages postés 292 Date d'inscription mercredi 25 octobre 2006 Statut Membre Dernière intervention 27 novembre 2009
7 nov. 2006 à 03:09
ok merci pour cette correction Gobillot ...moi j'vais faire dodo
bonne fin de soirée
0
mortalino Messages postés 6786 Date d'inscription vendredi 16 décembre 2005 Statut Membre Dernière intervention 21 décembre 2011 18
7 nov. 2006 à 06:28
Vous me faites sourire avec toutes vos variables et boucles imbriquées...
Je n'insiste pas mais je conseille (et dernier post sur ce topic) : la Collection est la plus adaptée.

@++

<hr width="100%" size="2" />
  --Mortalino--
Le mystérieux chevalier, "Provençal, le Gaulois"
/DIV>
0
cs_DARKSIDIOUS Messages postés 15814 Date d'inscription jeudi 8 août 2002 Statut Membre Dernière intervention 4 mars 2013 130
7 nov. 2006 à 06:49
Juste tout de même une petite remarque sur ce que j'ai pu lire ici et là : les collections sont adaptées pour cà ? NON, les collections sont faîtes pour stocker des objets, pas pour trier des données et encore moins faire du comptage de ligne d'un tableau sans doublons. L'inconvénient des collections ? Elles prennent des ressources (beaucoup !!!), et surtout, pour un nombre important d'objets, elles deviennent très très lentes par rapport à un simple tableau !!! Cependant, si on se limite à un petit nombre de ligne dans le tableau, c'est peut-être une solution simple à implémenter, et rapide à éxécuter (bien que le déclenchement d'erreur va apporter de la lourdeur !!!).

Un code plus court est plus rapide : NON NON NON ! C'est très souvent le contraire : il vaut mieux un code long mais optimisé, qu'un code très court, qui bouffe énormément de ressources, et qui au final sera plus long à éxécuter !

Il faut réfléchir au niveau de la compléxité : tri d'un tableau en n * log (n) en tri de dikjstra, puis compléxité en temps linéaire pour compter les doublons.
Trouver les doublons sans tri préalable : compléxité en n² !!! Donc moins efficace !

Là encore, il faut beaucoup de lignes pour que ca soit perceptible, mais pour un grand tableau, c'est loin d'être négligeable !
0
nicobox2 Messages postés 23 Date d'inscription lundi 7 novembre 2005 Statut Membre Dernière intervention 14 décembre 2006
7 nov. 2006 à 11:25
Bonjour à tous,

J'ai testé 4 codes que vous avez fait ... ca marche pas...

Dans mon cas j'ai un tableau qui contient :

proc1
proc2
proc1
proc1

Ca devrait renvoyer 2 hors dans la majorité de vos codes ca renvoie 3 ...
0
nicobox2 Messages postés 23 Date d'inscription lundi 7 novembre 2005 Statut Membre Dernière intervention 14 décembre 2006
7 nov. 2006 à 11:41
Ton code ne semble pas marcher dans certains cas :

J'ai tableau qui contient :

XU1 PROCESSOR
XU1 PROCESSOR

Renvoie 1 donc OK dans ce cas.

Par contre dans ce tableau

Proc 1
Proc 2
Proc 1
Proc 1

Ca renvoie 3 ... ca devrait renvoyer 2 ...

Tu vois pourquoi ?
0
mortalino Messages postés 6786 Date d'inscription vendredi 16 décembre 2005 Statut Membre Dernière intervention 21 décembre 2011 18
7 nov. 2006 à 11:41
Beh avec ma technique, ça fonctionne :

Private Sub Test()
    Dim sTableau(1 To 4)    As String
    Dim i                   As Byte
    Dim cCollection         As New Collection
    
sTableau(1) =  "proc1"
sTableau(2) = "proc2"
sTableau(3) = "proc1"
sTableau(4) = "proc1"
' *** seul 1, 2 et 3 devra rester

    On Error Resume Next
' l'ajout d'un doublon provoque une erreur, on occulte l'erreur,
' l'ajout du doublon ne se fait pas et la routine continue  ;)

For i = LBound(sTableau) To UBound(sTableau)
    cCollection.Add sTableau(i), CStr(sTableau(i))
Next i
For i = 1 To cCollection.Count
    Debug.Print cCollection.Item(i)
Next i

End Sub

~<small> Mortalino </small>~

Resultat débug.Print :
proc1
proc2

@++





<hr width ="100%" size="2" />

  --Mortalino--
Le mystérieux chevalier, "Provençal, le Gaulois"
/DIV>
0
nicobox2 Messages postés 23 Date d'inscription lundi 7 novembre 2005 Statut Membre Dernière intervention 14 décembre 2006
7 nov. 2006 à 11:52
En vbscript ca marche pas ...
Il doit avoir des choses à changer dans le code ... les collections par exemple je suis pas sur que ca fonctionne en vbs.
0
mortalino Messages postés 6786 Date d'inscription vendredi 16 décembre 2005 Statut Membre Dernière intervention 21 décembre 2011 18
7 nov. 2006 à 12:00
Oui, c'est possible, essaie de voir avec l'aide de M$ Script Editor

@++

<hr width="100%" size="2" />
  --Mortalino--
Le mystérieux chevalier, "Provençal, le Gaulois"
/DIV>
0
chaibat05 Messages postés 1883 Date d'inscription samedi 1 avril 2006 Statut Membre Dernière intervention 20 novembre 2007 2
7 nov. 2006 à 13:21
Salut tout le monde,


Mortalino :
^^Vous me faites sourire avec toutes vos variables ...
tu nous reproches les variables alors que
tu en fais toute une collection


C' est vrai qu' avec ma fonction je suis parti du principe
que le tableau était trié,


Au cas ou il ne le ne serait pas


Function Compte_Sans_Doublon() As integer
  Dim uB as integer
  uB=UBound(T)
  if uB<2  Then
     Compte_Sans_Doublon=uB 
  Else
     Dim i as Integr, y as integer, sText As string,
      'plus de Temp() on fait l' économie d' un tableau
      'qui ne sert à rien, sauf si on veut afficher le résultat
     Dim sList As ListBox
     'on copie le tout dans sList
     For i= 1 to uB
         sList.AddItem T(i)
     Next
     'on trie
     sList.Sort=True  
     uB=uB-1
     y=0
    For i=1 To uB
       sText=sList.List(i)
       y=y+1
       Do While (i<uB) And (sText=sList.List(i+1))
            i=i+1
       Loop
    Next
   Compte_Sans_Doublon=y
End Function


'------------------------------------------
et c' est mon dernier mot !
0
Rejoignez-nous