Boucle à l'envers

BenHarber

XLDnaute Occasionnel
Bonjour Le Forum,
Pour passer en revue une zone déterminée (que je nomme 'znWrk') j'ai pris l'habitude d'utiliser le type de code suivant :

Dim znWrk As Object, cWrk As Object
Set znWrk = ThisWorkbook.Sheets(1).Range("A1:A" & Sheets(1).[A65536].End(xlUp).Row)
For Each cWrk In znWrk
'TRAITEMENT macro'
Next cWrk

Je passe ainsi en revue chaque cellule de la zone en ORDRE CROISSANT, càd en partant de 'A1' jusqu'à la dernière cellule non vide de la colonne A.

Question : y-a-t-il possibilité de les passer en revue dans l'odre DECROISSANT (càd de la dernière cellule non vide de la colonne A jusqu'à 'A1'). Si oui, quel est le code ?

Merci d'avance pour vos suggestions.

PS : je connais le truc qui consiste à mettre en variable le n° de la ligne de la dernière cellule, puis à faire une boucle décroissante du style :
i=[A65536].End(xlUp).Row
For j = i to 1 Step -1
....etc....

Là, je voudrais savoir s'il existe une possibilité de balayer directement ''à l'envers'' une collection d'objets...(mais peut-être que cela n'existe pas !!??)

Cordialement,
BenHarber
 

patricktoulon

XLDnaute Barbatruc
bonjour
je ne vois pas l'intérêt de ce stratagème mais oui c'est possible
la boucle for each servirait uniquement a répéter l'itération
  1. on prend une plage
  2. on détermine le cells.count(variable (i))
  3. on boucle for each
  4. on itère i de -1 a chaque tours

démonstration
VB:
Sub test()
    Dim plage As Range, i&
    Set plage = Range("a1:f3")
    i = plage.Cells.Count
    For Each cel In plage.Cells
        t = t & plage.Cells(i).Address(0, 0) & vbCrLf
       If i > 1 Then i = i - 1
    Next
    MsgBox t
End Sub

je le redis je ne vois pas l'intérêt d'utiliser for each sachant que l'on peut boucler a reculons
de cells.count à 1 d'une plage
on obtient le même résultat
demonstration
VB:
Sub test2()
    Dim plage As Range, i&
    Set plage = Range("a1:f3")
    For i = plage.Cells.Count To 1 Step -1
        t = t & plage.Cells(i).Address(0, 0) & vbCrLf
    Next
    MsgBox t
End Sub
 

patricktoulon

XLDnaute Barbatruc
Bonsoir Patrick,
C'est ridicule de faire un for each qui ne peut être que croisant et de faire un i-1

Ceci dit il y a quelqu'un qui t'a décrementé ton for each à -1

Tu pouvais préciser qu'il s'agissait d'une blague !
bonjour robert
ben oui c'est ridicule mais c'est la demande
c'est bien pour ça que j'ai montré la bonne méthode ensuite ;)
mais bon la discussion date un peu, peut être a l'époque y avait il un intérêt quelconque
 

laurent950

XLDnaute Barbatruc
Bonsoir @patricktoulon, @dysorthographie , @Dranreb , le forum


VB:
Sub BoucleALenvers()
Dim znWrk As Range
Dim cWrk As Range
Dim i As Long: i = 0

Set znWrk = ThisWorkbook.Sheets(1).Range("A1:A" & Sheets(1).[A65536].End(xlUp).Row)

' Parcour le tableau avec les cellules dans l'ordre normal.
For Each cWrk In znWrk
    ' Parcourir le tableau à l'envers
    Debug.Print znWrk.Cells((znWrk.Count) - i, znWrk.Column).Value ' Exemple de traitement
    i = i + 1
Next cWrk

End Sub
 

laurent950

XLDnaute Barbatruc
Bonsoir @patricktoulon, @dysorthographie , @Dranreb , le forum

Boucle à l'envers (Avec For Each) et variable Object Range.

Il n'y a pas besoin de cette variable finalement.
dim i as long

VB:
Sub BoucleALenvers()
    Dim znWrk As Range
    Dim cWrk As Range

    Set znWrk = ThisWorkbook.Sheets(1).Range("A1:A" & Sheets(1).[A65536].End(xlUp).Row)

    ' Parcourir la plage avec For Each, mais traiter en sens inverse
    For Each cWrk In znWrk
        ' Utiliser directement l'index basé sur Row dans l'ordre inverse
        Debug.Print znWrk.Cells(znWrk.Count - (cWrk.Row - znWrk.Cells(1, 1).Row), 1).Value
    Next cWrk
End Sub
 
Dernière édition:

mapomme

XLDnaute Barbatruc
Supporter XLD
Bonsoir à tous :),

Bon, toutes les pseudo solutions utilisent un indice i qui doit être décrémenté dans une boucle For Each.. Next. Ce sont des boucles avec indice.

Autant boucler directement sur l'indice i For i = ... To 1 Step -1, ça fera moins de lignes de code!

BenHarber avait écrit jadis :

Tu as raison Roger : je recherche éventuellement une solution style "For Each... ...Next qui fonctionnerait "à l'envers" (Et n'allez pas croire que c'est une blague belge qui consisterait à remonter la boucle...à l'Anvers !)

Donc la réponse reste NON !
 
Dernière édition:

laurent950

XLDnaute Barbatruc
Re @mapomme

oui c'est vrai maintenant je n'utilise que les variables objets.

VB:
Sub BoucleALenvers()
    Dim znWrk As Range
    Dim cWrk As Range

    ' Définir la plage znWrk
    Set znWrk = ThisWorkbook.Sheets(1).Range("A14:A" & Sheets(1).[A65536].End(xlUp).Row)

    ' Parcourir la plage avec For Each, mais traiter en sens inverse
    For Each cWrk In znWrk
        ' Utiliser directement l'index basé sur Row dans l'ordre inverse
        Debug.Print ThisWorkbook.Sheets(1).Cells(znWrk.Cells(znWrk.Cells.Count).Row - (cWrk.Row - znWrk.Row), znWrk.Column).Value
    Next cWrk
End Sub
.
 
Dernière édition:

jurassic pork

XLDnaute Occasionnel
Hello,
voici une solution sans "bricolage" à l'intérieur du For Each. J'utilise la classe stdEnumerator du projet stdVBA. Cette classe à une méthode Reverse qui permet d'inverser les éléments d'un objet énumérable comme le Range par exemple.
Voici un exemple de code :
VB:
Sub TestEnumerator()
Dim myEnumerator As stdEnumerator, elem
Set myEnumerator = stdEnumerator.CreateFromIEnumVariant(Range("A2:A86"))
For Each elem In myEnumerator.Reverse()
   Debug.Print elem
Next elem
End Sub
Dans cet exemple j'affiche les valeurs de cellules de A86 à A2
Pour que cela fonctionne , il faut charger les modules de classe stdEnumerator.cls et stdICallable.cls (qui se trouvent ici) dans son projet. Attention cela ne fonctionne que pour Windows.
Pour 85 éléments le CreateFromIEnumVariant met 300 us (110 ms pour 65536 éléments). C'est sûr que cela fait perdre du temps par rapport à une solution à l'intérieur du For Each.
Ami calmant, J.P
 

mapomme

XLDnaute Barbatruc
Supporter XLD
Bonjour @jurassic pork ;),

Cela fonctionne (pour ça, je te fais confiance) mais au prix d'un élément tiers stdVBA, non ? C'est intéressant mais ce n'est pas une méthode native (et c'est dommage). Est ce que je me fourvoie ?

Pour toutes ces méthodes, il faut savoir comment sont "rangés" les éléments de la collection et quel est l'ordre de parcours fait par le For..Each pour parler de boucle inversée. A mon humble avis seule une programmation via des indices peut forcer l'ordre que l'on souhaite. Donc pour moi :
  • si cet ordre est connu sans ambiguité, je peux utiliser un For Each pour parcourir de manière ordonnée une collection
  • si cet ordre n'est pas connu et si c'est possible, j'utilise des boucles For i= pour parcourir selon l'ordre que je souhaite.
Je suis prêt bien entendu à évoluer grâce à vous tous...
 

Tlorf

XLDnaute Nouveau
@patricktoulon, merci pour votre réponse. Bon en effet je me suis un peu compliqué la tâche, j'ai bricolé avec ce que je connaissais. Je ne connaissais pas la forme d'écriture "plage.Cells(i).Address(0, 0)", que j'ai transformé en "plage.Cells(i).Value" et cela règle mon problème.
Aussi j'avais rencontré une difficulté : vous saviez que lorsque l'on fait un for each cell dans une sub cela teste les cellules dans l'ordre mais lorsqu'on le fait dans une fonction, cela les teste en partant de la dernière ? Pourquoi ça ?
 

jurassic pork

XLDnaute Occasionnel
Cela fonctionne (pour ça, je te fais confiance) mais au prix d'un élément tiers stdVBA, non ? C'est intéressant mais ce n'est pas une méthode native (et c'est dommage). Est ce que je me fourvoie ?

Pour toutes ces méthodes, il faut savoir comment sont "rangés" les éléments de la collection et quel est l'ordre de parcours fait par le For..Each pour parler de boucle inversée. A mon humble avis seule une programmation via des indices peut forcer l'ordre que l'on souhaite. Donc pour moi :
  • si cet ordre est connu sans ambiguité, je peux utiliser un For Each pour parcourir de manière ordonnée une collection
  • si cet ordre n'est pas connu et si c'est possible, j'utilise des boucles For i= pour parcourir selon l'ordre que je souhaite.
Effectivement cela demande un élément tiers qu'il faut importer dans son projet. Je donnais cela à titre indicatif car dans le cas présent on s'en sort autrement. Mais en fait je répondais à la demande initiale :
Là, je voudrais savoir s'il existe une possibilité de balayer directement ''à l'envers'' une collection d'objets...(mais peut-être que cela n'existe pas !!??)
Quand à l'ordre dans le cas d'un range le reverse balaie bien la plage dans l'ordre inverse.
et avec le stdEnumerator on peut ordonner les éléments avec un Sort :
Sort(Optional ByVal cb as stdICallable<(item: Variant, key: Variant)=>Variant> = nothing) as stdEnumerator
Sort the enumerator contents by the value retrieved by either the values in the enumerator or the values returned by cb.
 

Discussions similaires

Réponses
4
Affichages
266

Statistiques des forums

Discussions
314 638
Messages
2 111 476
Membres
111 161
dernier inscrit
KARIMTAPSO