Boucle For Next imbriquée [Résolu]

robby98800 64 Messages postés mardi 29 mai 2012Date d'inscription 27 juillet 2012 Dernière intervention - 27 juin 2012 à 07:20 - Dernière réponse : robby98800 64 Messages postés mardi 29 mai 2012Date d'inscription 27 juillet 2012 Dernière intervention
- 22 juil. 2012 à 23:58
Bonjour à tous,

j'ai fait une macro qui compare d'abord une cellule d'une colonne à une autre et qui compare ensuite (si la 1ere condition est bonne) une autre cellule d'une autre colonne à 2 autres(la valeur dans la 1ere doit être encadré par les 2 valeurs dans les deux autres). Si toutes les conditions sont remplis on écrit dans une cellule, sinon on incrémentre la boucle.

C'est assez compliqué à s'en faire une image je vous met en pièce jointe un exemple : http://cjoint.com/?0FBhtQ6Ssmj

La macro ressemble à ca :
Sub position()
For i = 2 To Sheets(2).Range("C" & Rows.Count).End(xlUp).Row
    For j = 2 To Sheets(3).Range("A" & Rows.Count).End(xlUp).Row
    
        If Sheets(2).Range("C" & i) = Sheets(3).Range("A" & j) Then
            If Sheets(2).Range("F" & i) >= Sheets(3).Range("B" & j) And Sheets(2).Range("F" & i) <= Sheets(3).Range("C" & j) Then
                Sheets(2).Range("G" & i) = "couche"
            Else: Sheets(2).Range("G" & i) = ""
            End If
    Next j
        
        End If
    Next j

Next i
        
    
End Sub


Le problème est que j'obtiens l'erreur : erreur de compilation Next sans For à la ligne du premier Next j.

Merci de votre aide !
Afficher la suite 

86 réponses

Répondre au sujet
cs_cheyenne 693 Messages postés samedi 18 mai 2002Date d'inscription 17 avril 2017 Dernière intervention - 27 juin 2012 à 19:24
+3
Utile
Re,

Erreur de ma part :
le deuxième fin_sh2 est à remplacer évidement par fin_sh3.

Utiliser également With
Sub position()
   Dim i       As Long
   Dim j       As Long
   Dim fin_sh2 As Long
   Dim fin_sh3 As Long

   fin_sh2 = Sheets(2).Range("C" & Rows.Count).end(xlUp).Row
   fin_sh3 = Sheets(3).Range("A" & Rows.Count).end(xlUp).Row
   
   With Sheets(2)
      For i = 2 To fin_sh2
         For j = 2 To fin_sh3
            
            If .Cells(i, 3).Value = Sheets(3).Cells(j, 1).Value Then
               
               If .Cells(i, 6).Value >= Sheets(3).Cells(j, 2).Value Then
                  If .Cells(i, 6).Value <= Sheets(3).Cells(j, 3).Value Then
                     .Cells(i, 7).Value = "couche"
                  Else
                     .Cells(i, 7).Value = "debout"
                  End If
               End If
   
            End If

         Next j
      Next i
   End With
End Sub

Cheyenne
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de cs_cheyenne
ucfoutu 18039 Messages postés lundi 7 décembre 2009Date d'inscriptionContributeurStatut 11 avril 2018 Dernière intervention - 2 juil. 2012 à 07:00
+3
Utile
Ecoute,
Je ne veux pas reprendre tout (analyse des tenants et aboutissants)

je vais me contenter de repartir du code que tu as montré le mercredi 27 juin 2012 à 09:08:18 en disant qu'il fonctionnait, mais auquel tu reprochais simplement d'être lent. C'est le mécanisme de ton propre code, que je vais appliquer, mais en utilisant deux tableaux dynamiques ===>>
Voilà ce qu'il deviendrait :
derlig2 = Sheets("Feuil2").Range("C" & Rows.Count).End(xlUp).Row
derlig3 = Sheets("Feuil3").Range("A" & Rows.Count).End(xlUp).Row
tablo2 = Sheets("Feuil2").Range("A2:G" & derlig2)
tablo3 = Sheets("Feuil3").Range("A2:C" & derlig2)
For i = 1 To UBound(tablo2)
  For j = 1 To UBound(tablo3)
    If tablo2(i, 3) = tablo3(j, 1) Then
      If tablo2(i, 6) >= tablo3(j, 2) Then
        If tablo2(i, 6) <= tablo3(j, 3) Then
          tablo2(i, 7) = "couche"
        Else
          tablo2(i, 7) = "debout"
        End If
      End If
    End If
  Next
Next
Sheets("Feuil2").Range("A2:G" & derlig2) = tablo2



________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de ucfoutu
ucfoutu 18039 Messages postés lundi 7 décembre 2009Date d'inscriptionContributeurStatut 11 avril 2018 Dernière intervention - 27 juin 2012 à 08:13
0
Utile
Bonjour,
Avant d'aller où que ce soit et de commencer à examiner plus en détail :
Tu as deux next j qui sautent aux yeux !!!!!



________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
Commenter la réponse de ucfoutu
robby98800 64 Messages postés mardi 29 mai 2012Date d'inscription 27 juillet 2012 Dernière intervention - 27 juin 2012 à 08:37
0
Utile
Oui je pensais qu'on devait mettre un next à chaque sortie de If mais je viens de m'apercevoir qu'en enlevant le premier le raisonnement reste correct.
Il n'y a plus d'erreur généré cependant je n'ai pas l'impression que la macro fonctionne car aucun de mes cellules n'affiche "couche" alors que les conditions semblent être remplis.

Je vais faire des tests..
Commenter la réponse de robby98800
robby98800 64 Messages postés mardi 29 mai 2012Date d'inscription 27 juillet 2012 Dernière intervention - 27 juin 2012 à 09:08
0
Utile
Je viens de faire une modification
Sub position()
For i = 2 To Sheets(2).Range("C" & Rows.Count).End(xlUp).Row
    For j = 2 To Sheets(3).Range("A" & Rows.Count).End(xlUp).Row
    
        If Sheets(2).Range("C" & i) = Sheets(3).Range("A" & j) Then
            If Sheets(2).Range("F" & i) >= Sheets(3).Range("B" & j) Then
                If Sheets(2).Range("F" & i) <= Sheets(3).Range("C" & j) Then
            Sheets(2).Range("G" & i) = "couche"
                
            Else: Sheets(2).Range("G" & i) = "debout"
                
                End If
            End If

        
        End If
    Next j

Next i
        
    
End Sub

     


Comme ça, ça fonctionne apparemment c'était le And qui posait un problème (le fait que le couche ne s'affiche pas). Par contre l'exécution est très longue.
Commenter la réponse de robby98800
cs_cheyenne 693 Messages postés samedi 18 mai 2002Date d'inscription 17 avril 2017 Dernière intervention - 27 juin 2012 à 13:52
0
Utile
Bonjour,

Optimisation :
Remplacer la borne supérieure des boucles par des variables.
fin_sh2 = Sheets(2).Range("C" & Rows.Count).End(xlUp).Row
fin_sh2 = Sheets(3).Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To fin_sh2
   For j = 2 To fin_sh3

Ce qui évite un calcul à chaque passage.

Puis indiquer ce que tu dois extraire de chaque Range, en l'occurrence Value, cela évitera à Excel d'interpréter ce que tu veux.
If Sheets(2).Range("C" & i).Value = Sheets(3).Range("A" & j).Value Then

Si tu as beaucoup de lignes à explorer utiliser plutôt Cells que Range afin d'éviter les concaténations.
If Sheets(2).Cells(i, 3).Value = Sheets(3).Cells(j ,1).Value Then

Cheyenne
Commenter la réponse de cs_cheyenne
cs_cheyenne 693 Messages postés samedi 18 mai 2002Date d'inscription 17 avril 2017 Dernière intervention - 27 juin 2012 à 13:57
0
Utile
Re,

J'ai oublié de te recommander de mettre le
ScreenUpdating à False en début de procédure et de le rétablir avant de quitter celle-ci.

Cheyenne
Commenter la réponse de cs_cheyenne
robby98800 64 Messages postés mardi 29 mai 2012Date d'inscription 27 juillet 2012 Dernière intervention - 28 juin 2012 à 09:02
0
Utile
Merci beaucoup Cheyenne pour ta réponse et tes explications ça marche beaucoup mieux et ça m'a permis d'y voir plus clair en vba !

Juste une question si dans une condition If on ne met pas de Else (car on ne veux rien faire sinon) le code fonctionne t-il toujours ?

Merci,

Robin
Commenter la réponse de robby98800
ucfoutu 18039 Messages postés lundi 7 décembre 2009Date d'inscriptionContributeurStatut 11 avril 2018 Dernière intervention - 28 juin 2012 à 10:16
0
Utile
Ta question trouve sa réponse dans ton aide VBA !
Et tu en as de surcroît un exemple dans le code de cheyenne, non ? (le premier bloc If ne comprend aucune clause Else.


________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
Commenter la réponse de ucfoutu
cs_cheyenne 693 Messages postés samedi 18 mai 2002Date d'inscription 17 avril 2017 Dernière intervention - 28 juin 2012 à 12:41
0
Utile
Bonjour robby98800,

La clause Else n'est en aucun cas indispensable.
(voir la réponse de ucfoutu)

Dans l'exemple de code j'ai oublié ce que je t'avais préconisé, HI

Sub position()
   Dim i       As Long
   Dim j       As Long
   Dim fin_sh2 As Long
   Dim fin_sh3 As Long

   fin_sh2 = Sheets(2).Range("C" & Rows.Count).end(xlUp).Row
   fin_sh3 = Sheets(3).Range("A" & Rows.Count).end(xlUp).Row

   Application.ScreenUpdating = False  ' <<<<<

   '  le code...

   Application.ScreenUpdating = True  ' <<<<<
End Sub

Tu devrais avoir ainsi une nette amélioration du temps d'exécution, surtout si tu as beaucoup de lignes à traiter.

Cheyenne
Commenter la réponse de cs_cheyenne
ucfoutu 18039 Messages postés lundi 7 décembre 2009Date d'inscriptionContributeurStatut 11 avril 2018 Dernière intervention - 28 juin 2012 à 13:32
0
Utile
Pas de secrets :
La seule manière vraiment efficace d'accélerer considérablement les choses est à mon sens :
- de créer un tableau dynamique
- de traiter les éléments de ce tableau
- de réinjecter le tableau, d'un seul coup.

Gain considérable (traitement des éléments d'un tableau bien plus rapide que celui des éléments d'une plage, puis réinsertion d'un seul coup, encore plus rapide).
Tout le reste ne sera à mes yeux que "diminuer la douleur", sans s'attaquer à "la lourdeur".



________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
Commenter la réponse de ucfoutu
cs_cheyenne 693 Messages postés samedi 18 mai 2002Date d'inscription 17 avril 2017 Dernière intervention - 28 juin 2012 à 14:00
0
Utile
Bonjour ucfoutu,

Certes oui !

1) Mais il faut bien auparavant renseigner ce tableau à partir des plages de données...

2) Le traiter en mémoire est effectivement beaucoup plus rapide !

3) Comment le réinjecter d'un seul coup sans passer par une boucle pour inscrire les données traitées ?

Un tout petit exemple serait le bienvenu. Merci.


Bonne journée à toi,

Cheyenne
Commenter la réponse de cs_cheyenne
ucfoutu 18039 Messages postés lundi 7 décembre 2009Date d'inscriptionContributeurStatut 11 avril 2018 Dernière intervention - 28 juin 2012 à 15:03
0
Utile
Bonjour, cheyenne,
La réinjection d'un tableau se fait de la manière la plus simple du monde.
Regarde donc :
 Dim tablo(1 To 10, 1 To 3)
' 1) _______ juste pour créer un tableau exemple _____________
For i = 1 To 10
  For j = 1 To 3
   tablo(i, j) = "a" & i & j
  Next
 Next
' 2) _______________ on l'injecte ainsi 
 Range("A1:C10") = tablo

aucun problème !

________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
Commenter la réponse de ucfoutu
cs_cheyenne 693 Messages postés samedi 18 mai 2002Date d'inscription 17 avril 2017 Dernière intervention - 28 juin 2012 à 15:20
0
Utile
Re,

Range("A1:C10") = tablo

Ben oui, évidemment, arggghhhh !!!!
que n'y ai je pas pensé plus tôt ?

Il n'empêche qu'au départ il faut bien renseigner le tableau en parcourant les cellules de la plage.
Mais ce "temps perdu" sera largement compensé par le traitement en mémoire et au final par l'injection en bloc.

Merci pour l'exemple.

Cheyenne
Commenter la réponse de cs_cheyenne
ucfoutu 18039 Messages postés lundi 7 décembre 2009Date d'inscriptionContributeurStatut 11 avril 2018 Dernière intervention - 28 juin 2012 à 17:07
0
Utile
Il n'empêche qu'au départ il faut bien renseigner le tableau en parcourant les cellules de la plage.

Ben non !
regarde (en imaginant que tu aies des données dans la plage A1:D5
tablo = Range("A1:D5") ' le voilà, ton tableau
' on va le traiter (faire ici semblant en ajoutant "vu ?" à chaque élément
For i = 1 To UBound(tablo, 1)
   For j = 1 To UBound(tablo, 2)
     tablo(i, j) = tablo(i, j) & "vu ?"
   Next
Next
Range("A1:D5").Value = tablo

Je n'ai ici à aucun moment blouclé sur la plage (lent), mais sur le tableau (10 fois plus rapide).
________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
Commenter la réponse de ucfoutu
cs_cheyenne 693 Messages postés samedi 18 mai 2002Date d'inscription 17 avril 2017 Dernière intervention - 28 juin 2012 à 17:31
0
Utile
Re,

Ah ben oui, SUPER !
Je ne savais, je le reconnais, que l'on pouvait remplir un tableau de cette manière.

J'ai déclaré tablo en tant que Variant et effectué divers essais avec des cellules "numériques" et "textes". Impeccable.

Je vais de ce pas revoir les codes de certaines de mes applications.

Un grand merci pour l'astuce que je valide virtuellement

Cheyenne
Commenter la réponse de cs_cheyenne
robby98800 64 Messages postés mardi 29 mai 2012Date d'inscription 27 juillet 2012 Dernière intervention - 28 juin 2012 à 23:08
0
Utile
Merci aussi ucfoutu, je vais essayer d'adapter ta méthode.
Commenter la réponse de robby98800
robby98800 64 Messages postés mardi 29 mai 2012Date d'inscription 27 juillet 2012 Dernière intervention - 29 juin 2012 à 06:47
0
Utile
Re,

Voici ce que j'ai fait. Je suis passé par deux tableaux, un dynamique et un fixe.
Sub tabex()
derniere_ligne = Sheets(2).Range("C1").End(xlDown).Row
Dim tab_exa()
ReDim tab_exa(derniere_ligne - 2, 2)

Dim tab_exb(215, 2)
    
    For i = 2 To derniere_ligne - 2
        tab_exa(i, 0) = Sheets(2).Range("C" & i + 2)
        tab_exa(i, 1) = Sheets(2).Range("F" & i + 2)
        tab_exa(i, 2) = Sheets(2).Range("G" & i + 2)

    Next i
    
    For j = 2 To UBound(tab_exb, 1)
            tab_exb(j, 0) = Sheets(3).Range("A" & j)
            tab_exb(j, 1) = Sheets(3).Range("B" & j)
            tab_exb(j, 2) = Sheets(3).Range("C" & j)
    
    Next j
    
    For i = 2 To UBound(tab_exa, 1)
        For j = 2 To UBound(tab_exb, 1)
            If tab_exa(i, 0) = tab_exb(j, 0) Then
                If tab_exa(i, 1) >= tab_exb(j, 1) And tab_exa(i, 1) <= tab_exb(j, 2) Then
                    tab_exa(i, 2).Value = "couche"
               
                End If
            End If
    
        Next j
    Next i

Range("G2:G" & [G65536].End(xlUp).Row).Value = tab_exa(i, 2)

End Sub


J'imagine bien que la dernière ligne est fausse mais je ne sais pas comment dire la 3eme colonne du tab_exa est égale à la plage de cellule de la colonne G. En effet la colonne G a le meme nombre de ligne que la colonne A mais le nombre est variable.
De plus je sais très bien que la dernière ligne ne peut pas fonctionner car j'écrit affecte le tab_exa(i, 2) aux cellules de G2 jusqu'à la dernière cellule de G non vide mais elles ne sont pas remplies avant l'affectation donc ça ne peut pas marcher.

C'est d'ailleurs pour cela que j'obtiens l'erreur 9 l'indice n'appartient pas à la sélection à la derniere ligne.

Je trouve cette méthode très puissante et j'aimerais vraiment avoir plus d'infos pour pouvoir bien la maitriser.

Merci,

Robin
Commenter la réponse de robby98800
ucfoutu 18039 Messages postés lundi 7 décembre 2009Date d'inscriptionContributeurStatut 11 avril 2018 Dernière intervention - 29 juin 2012 à 07:21
0
Utile
Bonjour, robby98800,


Lorsque tu fais une boucle For to next (ex : for x = 1 to 2), la variable d'avancement (ici x, donc) avance d'une unité à chaque tour de boucle. A la fin de la boucle, elle dépasse donc sa limité d'une unité.
Fais l'essai :
For x = 1 to 2
 ' on s'en moque
next
msgbox x ' ===>> x vaut alors 2 + 1 = 3 et non 2


et (dans ton exemple, donc) i a dépassé d'une unité la borne supérieure de ton tableau tab_exa ===>> et tu es hors limite.
Utilise donc i-1 et non i dans ta dernière ligne

________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
Commenter la réponse de ucfoutu
ucfoutu 18039 Messages postés lundi 7 décembre 2009Date d'inscriptionContributeurStatut 11 avril 2018 Dernière intervention - 29 juin 2012 à 07:25
0
Utile
Ceci étant dit, tu as compris une partie seulement de l'utilisation des tableaux, dont je vois que tu les dimensionnes, puis les alimentes en boucle, au lieu de les générer directement (sans aucune boucle ni besoin de les dimensionner)
Relis donc plus attentivement ce que j'en ai dit plus haut


________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
Commenter la réponse de ucfoutu

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.

Boucle For Next imbriquée - page 2