Trouver un élément dans un tableau, facile pour qui s'y connait ! - VB/VBA/VBS - Programmation
Marsh Posté le 23-09-2007 à 20:29:59
tu as ces valeurs là sous excel ? c'est pas mieux une BDD Access ?
Marsh Posté le 23-09-2007 à 20:45:41
Si tu tiens à ton Tableau et si ce dernier est trié alors http://www.asp-php.net/tutorial/divers/dichotomie.php
sinon une bête feuille XL 256 x 65536 cellules et un find
Marsh Posté le 23-09-2007 à 21:02:03
Hum... Non, Access n'est pas mieux, parce qu'il y a plus de fonctions Excel pour les traitements parallèles que j'ai à faire.
Et non, mon tableau n'est pas trié, donc le dichotomie, ça marche pas !
Et un find implique que "j'écrives" mon tableau sur une feuille Excel, mais cette simple opération prend plus de temps que la boucle que je cherche à optimiser !
Marsh Posté le 23-09-2007 à 21:25:24
ton tableau tu le sors d'où au fait ? ca va piocher des infos où ?
sinon en passant par un fichier txt, ca devrait aller plus vite non ?
Marsh Posté le 24-09-2007 à 11:43:39
Bon, j'explique plus en détail... En fait, le but est de soumettre
un texte (stocké dans un fichier txt) au programme. Le but sera
alors de lister les différents mots présents dans le texte et, pour
chaque mot, de connaitre le nombre d'occurences.
Mon programme fonctionne comme suit :
1. Lecture du fichier : on stocke le contenu du
fichier texte dans une variable (ou on fait ça
en plusieurs fois selon la taille du fichier).
2. On met tout en minuscule et on vire tout ce qui
n'est pas une lettre ou un espace.
3. On vire les éventuels double-espaces.
4. On "sépare" les mots, donc pour ça, je cherche
le premier espace (avec un InStr) et ce qui est
à gauche, c'est mon mot, ce qui est à droite, c'est
ce qu'il reste à traiter. Et je boucle là-dessus.
Et donc, ce mot en question que je récupère, il y a
deux possibilités.
En fait, j'ai deux tableaux : TA et TB. TB(n) sera le
nombre d'occurences du mot TA(n).
La boucle fameuse boucle dont je parle cherche le petit
n pour lequel TA(n) = mot qu'on cherche.
Si n <> 0 alors TB(n) = TB(n) + 1
Par contre, si n = 0, alors on incrémente la variable MAX
(nombre total de mots), et on créé TA(MAX) et TB(MAX)
passe à 1.
Voilà !
Au final je n'ai plus qu'à écrire sur ma feuille Excel les
tableaux TA et TB.
Dans ce programme, ce qui met du temps, c'est la
boucle de découpage des mots. Le reste, c'est quasi
instantané.
Si vous voulez, voici la boucle en question :
Code :
|
Note : j'ai zappé le if P = 0 qui gère le dernier mot et
qui fait sortir de la boucle. C'est pas important.
Merci de vous pencher là-dessus !
Marsh Posté le 24-09-2007 à 11:48:12
oki,
bon alors moi je propose un truc peut être plus simple : commande batch
je ne maitrise pas assez le code pour te filer une ligne, mais à mon avis tu dois pouvoir faire un find du mot que tu cherches, et un compteur peux te refiler le nombre d'occurences. Le tout s'écrit alors dans un fichier fichier txt simple avec nom : nb_d'occurences.
Ca te donne une idée ?
Marsh Posté le 24-09-2007 à 13:10:38
Bah ça m'emballe pas trop, parce que si je bosse
sur un fichier texte, ok, je pourrai utiliser un Find
ou quelque chose dans ce gout-là, cependant,
les temps d'écritures sont plus lents en TXT qu'en
RAM, forcément. Donc au final, c'est même pas
dit que je sois gagnant.
Marsh Posté le 24-09-2007 à 13:26:19
Pour un tableau VB non trié, seule la recherche exhaustive peut marcher.
Il n'y a pas d'optimisation.
Toute solution passe par l'utilisation d'un tableau trié, d'un objet autre qu'un tableau (Collection, classe dédiée, expressions régulières via "Microsoft VBScript Regular Expressions 5.5" ) ou d'une autre solution (batch, composant externe, ...).
Marsh Posté le 24-09-2007 à 13:46:50
euh, tu peux juste nous indiquer le temps de traitement qui est "lent" stp ?
Marsh Posté le 24-09-2007 à 17:21:24
Sans problème. Prenons par exemple "Le petit chose", d'Alphonse Daudet.
1. Lecture du fichier et stockage dans une variable texte.
29 secondes
2. Formatage du texte (suppression des caractères autres que les lettres)
5 secondes
3. Suppression des double-espaces
12 secondes
4. Séparation des mots et calcul des occurences (code plus haut)
114 secondes
5. Affichage des données
4 secondes
Et conclusion (pour ceux que ça intéresse) :
88.008 mots, dont 8.590 différents.
Marsh Posté le 24-09-2007 à 17:35:32
J'ai pas de contraite particulière.
C'est juste que je trouve ça long, et que
j'aimerai abaisser ce temps le plus possible,
sans que ça m'oblige à faire des trucs trop
compliqués !
Marsh Posté le 25-09-2007 à 01:01:07
Qqs remarques
1. Lecture du fichier : on stocke le contenu du
fichier texte dans une variable (ou on fait ça
en plusieurs fois selon la taille du fichier).
Normalement tu peux lire séquentiellement un fichier texte
et le traiter ligne par ligne sans le "tronçonner"
et faire du LCase , Replace et autre dans la foulée
C'est vrai je n'ai pas de dispo "le petit chose" en texte pour faire une comparaison
Marsh Posté le 25-09-2007 à 09:17:59
Oui, bien sûr, je sais qu'on peut faire ça
ligne par ligne, mais bon, entre faire tourner
une fois le programme avec 2000 lignes ou
2000 fois avec une ligne, je ne sais pas si
ça fait une différence. Surtout que ça me
fait réitérer certaines opérations d'affichage
et ça, c'est très lent...
Marsh Posté le 25-09-2007 à 10:05:37
tiens d'ailleurs, si tu virais les affichages intermédiaires (si inutiles hein), ou que tu freezais l'écran ca accélérerait les étapes non ?
Marsh Posté le 25-09-2007 à 11:11:20
Bonjour,
Une suggestion qui vaut peut être pas grand chose ... (je connais rien au problème d'optimisation)
Pour le découpage de mots pourquoi ne pas utiliser Split et pour le comptage du nombre d'occurences de chaque mot le même Split avec Ubound.
Ca pourrait faire
TabResA = Split(MonTexte, " " )
Do While UBound(TabResA) > 0
TabResA = Split(MonTexte, " " )
nbocc = UBound(Split(MonTexte, TabResA(0)))
MonTexte = Replace(MonTexte, TabResA(0) & " ", "" )
msg = msg & vbCrLf & TabResA(0) & "=>" & nbocc
Loop
MsgBox msg
Marsh Posté le 25-09-2007 à 11:44:28
To thejulienlepage : Ta réponse est tout simplement stupide, la linéarité de ce genre de probleme est un leurre
Si en plus tu n'as pas utilisé Application.ScreenUpdating = False....Application.ScreenUpdating = True, ainsi que Application.EnableEvents
Marsh Posté le 25-09-2007 à 12:06:32
Merci bien les gars !
Le Split() va sûrement bien m'aider, et pareil
pour le Application.ScreenUpdating.
Je connaissais pas du tout !
M'enfin kiki29, de là à dire que ma réponse est "stupide",
c'est pas la peine ! Je connais pas, c'est vrai. C'est
pas être stupide !
C'est comme si je te disais "quoi ?! Tu parles pas
le bulgare ? Mais t'es stupide, c'est pourtant simple !"
Donc traite moi d'ignorant tant que tu veux, et honni
j'accepterai. En revanche stupide, évite !
Bon, je vais faire les changements appropriés et je vous
tiens au courant des résultats !
Marsh Posté le 25-09-2007 à 12:57:36
Bon, bah j'y pige que pouic, comme on dit.
La fonction Split() refuse mystérieusement
de fonctionner et me donne le message
d'erreur suivant :
"Erreur de compilation :
Nombre d'arguments incorrect ou affectation de propriété incorrecte"
J'ai marqué juste ça :
TAt = Split(T, " " )
TAt() et T étant de type String.
D'ailleurs, même si je marque TAt = Split("Texte bidon", " " ),
ça me fait la même chose.
Mais il y a un autre truc étrange : quand je tape
"Split(", la p'tite infobulle qui donne d'habitude les
arguments à mettre n'apparait pas, alors que le mot
clé "Split" est reconnu puisque quand je ne met pas
la majuscule sur le "S", il me la met.
Bref, faut-il faire quelque chose de spécial pour que
le Split fonctionne sous Excel ?
Marsh Posté le 25-09-2007 à 13:23:13
Es-tu sûr que c'est bien la syntaxe du Split qui pose problème ?
Si tu as une autre erreur de syntaxe, cela justifierait l'erreur et l'absence d'info-bulle, même pour le Split.
edit: après test, le split fonctionne parfaitement sous Excel 2007. Le problème est ailleurs.
Marsh Posté le 25-09-2007 à 13:36:26
Non, je n'ai pas d'autre erreur.
Quand je met le Split en commentaire, la
macro s'exécute.
En fait, quand je lance
le programme (qui est constitué de deux
macros), la première tourne, puis au moment
de lancer la seconde, il va directement sur la
ligne du Split et me met le message d'erreur.
Il refuse tout simplement d'entrer dans la macro.
Je ne sais pas si je suis très clair là...
En résumé, quand je lance le programme, il
ne commence même pas à exécuter la macro
et place le curseur sur la ligne du Split en me
mettant le message d'erreur.
Marsh Posté le 25-09-2007 à 13:45:53
1/ Si tu fais Debogage / Compiler est-ce que l'erreur est la même ?
2/ Fais voir le code concerné, y compris les déclarations des variables, sinon on ne pourra pas t'aider.
edit:
Tu peux aussi faire le test suivant : tu crées une nouvelle feuille Excel, tu actives l'éditeur VBA et, dans la fenêtre de debogage tu tapes
« ? split("bnefuih reuivh ireugb"," " )(1) » ou un truc du genre et tu fais ENTREE pour voir.
Marsh Posté le 25-09-2007 à 14:03:15
Ton TAt doit etre de type tableau
Tu peux donc mettre
Dim TAt as variant
Ca devrait fonctionner
en plus comme dirait Ki.. et quelque tu fais F1 (Aide en ligne)
Marsh Posté le 25-09-2007 à 14:14:23
Bah l'aide elle m'apprend rien de plus.
Et en ce qui concerne le type de TAt () (que j'ai renommé
Test d'ailleurs, mais on s'en fout), que je mette String,
Variant ou même rien du tout, ça ne change rien !
Voici mon code, si ça peut aider :
Code :
|
J'ai pas mis toute la partie que j'avais faite
pour le traitement (que j'espère pouvoir modifier
avec le fameux Split), mais ça n'a pas d'incidence
sur le programme, car j'ai tout mis en commentaires.
À part ça, le code est le même chez moi et bug
toujours sur le Split.
Marsh Posté le 25-09-2007 à 14:26:18
En ligne 21 tu redéfinis la fonction Split...
Quand tu l'appel en ligne 97...c'est la tienne qu'il tente d'executer...
Je pense qu'en changeant le nom de ta fonction Split ca devrait aller mieux...
Marsh Posté le 25-09-2007 à 14:28:08
Argh !!! Qu'est-ce que je suis naze !
J'avais même pas fait gaffe au fait que
ma fonction s'appelait Split !
Merci Paul Hood ! (de la famille de Robin ?)
Marsh Posté le 25-09-2007 à 14:29:43
pas tout à fait !!
Plus près de Jack Ryan que de Robin ...
Marsh Posté le 25-09-2007 à 15:28:16
Bon, bah mauvaise nouvelle : en utilisant la fonction suivante :
Code :
|
...j'obtiens un temps de calcul nettement plus long
qu'avec mon ancienne méthode...
Marsh Posté le 25-09-2007 à 16:03:46
Tu n'as pas besoins de la ligne 8 : Right etc...
Test = Split(T, " " )
i=0
Do While UBound(Test) > 0
Test = Split(T, " " )
TA(i,0)=Test(0)
TA(i,1)=UBound(Split(T, Test(0)))
T = Replace(T, Test(0) & " ", "" )
i=i+1
Loop
en fait tu remplaces le mot sélectionné et le blanc suvant par rien, ce qui diminue la string au fur et a mesure.
Dans ton tableau TA à 2 dimensions, la premiere c'est pour stocker le mot et la deuxième c'est pour le nombre d'occurences.
Marsh Posté le 25-09-2007 à 16:24:00
Bah oui, j'avais fait comme ça au début, mais...
0: "alphonse daudet le petit chose table des matières"
1: "daudet le petit chose table des matières"
2: "petit chose tab des matières"
...
Eh oui, c'est un peu embêtant !
Mais j'ai trouvé quelque chose qui fonctionne
pas mal et me baisse le temps d'exécution du
découpage des mots de 114 à 30 secondes en
faisant un mix entre mon ancienne méthode et
la tienne :
Code :
|
Marsh Posté le 25-09-2007 à 16:35:48
Si l'optimisation dans le traitement de chaînes VB6 vous intéresse, voici de quoi lire.
http://msdn2.microsoft.com/en-us/l [...] e.10).aspx
http://msdn.microsoft.com/library/ [...] topic1.asp
Marsh Posté le 23-09-2007 à 16:44:11
Salut à tous !
Voilà, j'ai un tableau TA(1 To Max), qui contient une
liste de mots (sans doublons), et je souhaite obtenir
l'indice (le numéro de ligne) d'un mot M donné.
Je bosse en VBA pour Excel, et j'ai le code suivant :
En sortie de boucle, je récupère une variable Trouve
qui vaut 0 si le mot n'est pas dans la table, et son
numéro de ligne s'il y est.
Je trouve ça assez peu optimisé (et je suis gentil),
et du coup, ça me ralenti pas mal mon programme
(j'ai Max qui vaut 50.000 actuellement, et ce nombre
va croitre jusqu'à 200.000 environ... Et cette boucle
va tourner plus de 30 millions de fois !!!).
Mais je ne vois pas d'autre méthode !
Est-il possible de faire ça plus rapidement ?
(sans boucle, se serait top)
Merci d'avance !
Message édité par Profil supprimé le 23-09-2007 à 18:34:54