Encore FIND

Salut le forum,

encore FIND, me direz-vous!

J'ai beau retourner l'affaire dans tous les sens, quelque chose m'échappe!

Le fichier joint est une histoire de mutation : des individus déposent de 1 à 6 demandes de mutation pour diverses zones en fonction desquelles, selon un système interne étranger à mon problème, ils ont un certain nombre de points.

Chaque zone dispose d'un nombre max de places disponibles.

Le but du code est de trouver qui seront les élus pour chaque zone sachant que c'est le nombre de points, jamais ex-aequo pour une même zone, qui sera prépondérant.

Où veux-tu en venir, Curulis?

Ok, voilà!

Mon système (largement déglingué par le code de Steelson ) fait appel à 2 boucles DO...LOOP dont l'une fait joujou avec FIND...FINDNEXT.

Pour un individu donné, déjà bien placé en ordre utile dans une zone, le code recherche dans la feuille 'Extract' toutes les autres demandes du même individu dont le n° de choix est supérieur, histoire de faire remonter la file de prétendants à ces autres zones.

Vous suivez?

Le souci? FINDNEXT ne trouve pas toutes les autres occurrences de cet individu, faussant par là-même le résultat en "oubliant" d'éliminer certaines demandes obsolètes dans certaines zones.

                With UsedRange
                    Set rCel = .Find(what:=.Cells(x, iCol - 3), lookat:=xlWhole)
                    If Not rCel Is Nothing Then
                        sAdr = rCel.Address
                        Do
                            If .Cells(x, iCol - 3) = "S8098a" Then MsgBox .Cells(x, iCol - 3) & "  " & iLevel & "  /  " & rCel.Value & "  " & CInt(rCel.Offset(0, 2).Value)
                            If CInt(rCel.Offset(0, 2).Value) > iLevel Then
                                If rCel.Row < 2 + CInt(.Cells(1, iCol - 2)) Then .Cells(1, rCel.Column + 3) = "!"
                                rCel.Resize(1, 4).Delete shift:=xlUp
                            End If
                            Set rCel = .FindNext(rCel.Value)
                        Loop While Not rCel Is Nothing And rCel.Address <> sAdr
                    End If
                End With

Pour vous aider à comprendre, prenez l'individu S8098a en 'Extract'[A4] Zone 1, choix 4.

Il est aussi en [E3] Zone 1, n°3, [BIW2] Zone 155, n°1 et [ELU2] Zone 74, n°2.

Le croirez-vous, le cas échéant, FINDNEXT s'arrête à la première occurrence rencontrée.

J'ai placé un MsgBox à son nom dans la boucle pour piéger l'affaire.

???

Je m'en remets à votre sagacité!

Double-clic en 'Extract' [A1] pour démarrer la macro.

Merci à vous,

A+

13grrrr-find.xltm (580.98 Ko)

Bonjour,

j'ai remarqué que findnext s'emmêle les pinceaux quand la plage de recherche est modifiée (dans ce cas-ci, le delete modifie la plage de recherche).

Salut le forum,

au moment où j'envoyais le post, j'avais l'intuition d'une réponse, confirmée depuis par une lecture (anglaise) expliquant qu'en supprimant le Range trouvé par FIND, la référence rCel ayant disparu, la recherche s'avère impossible à poursuivre.

If CInt(rCel.Offset(0, 2).Value) > iLevel Then

If rCel.Row < 2 + CInt(Cells(1, iCol - 2)) Then Cells(1, rCel.Column + 3) = "!"

rCel.Resize(1, 4).Delete shift:=xlUp

End If

Set rCel = UsedRange.FindNext(rCel)

Depuis, je cherche un moyen de contourner ce truc...

A+

Salut H2SO4,

merci de m'épauler...

J'ai aussi essayé avec...

Cells.Find

Là, on ne peut pas dire que la plage de recherche se modifie et le résultat est le même.

A+

Bonjour,

Une piste ?

If k = 0 Then
    Set Rng = rCel.Resize(1, 4)
        k = 1
Else
    Set Rng = Union(Rng, rCel.Resize(1, 4))
End If

Et tu supprimes ensuite rng quand tu le souhaites !...

Cdlt.

Bonjour,

Je n'ai pas vraiment lu ton code mais si tu veux faire des suppressions dans la plage durant une phase de recherche avec Find(), il serait préférable de stocker dans un tableau les adresses de cellules ou numéros de lignes puis après cette phase de recherche, effectuer les suppressions par rapport au valeurs du tableau en partant depuis le bas de la plage.

Une recherche Find() boucle sur la plage et si trouvé, reprend la recherche à partir de la cellule qui vient d'être trouvée, si elle est supprimée, FindNext() perd son repère !

Bonjour,

dans le cas où la plage est altérée, je n'utilise plus le findnext mais l'option after de l'instruction find.

ainsi

Sub testfind()
    strtofind = "chaine"

    Set re = Range("B2:B10").Find(strtofind)
    If Not re Is Nothing Then
        Do
            readr = re.Address
            re.EntireRow.Delete shift:=xlUp
            Set re = Range("B2:B10").Find(strtofind, after:=Range(readr))
        Loop Until re Is Nothing
    End If
End Sub

dans cet exemple toutes les lignes contenant l'occurrence dans la plage sont supprimées et l'on peut arrêter la boucle en testant nothing, s'il reste des occurrences, il faut également vérifier qu'on ne boucle pas indéfiniment sur la plage.

Bonjour,

personnellement je n'utilise plus que rarement .Findnext.

Je le remplace par .Find en imposant la cellule de départ :

.Find(ch1, LookIn:=xlValues, lookat:=xlWhole, After:=c)

Au moins je sais exactement où il en est.

Attention que c'est After le paramètre. Pour rechercher en colonne depuis A5 il faut lui mettre A4.

Ou bien lui indiquer la dernière cellule de la plage de recherche, il bouclera au début.

eric

Edit: bon on est raccord avec h2so4

Salut le forum,

au moment où j'envoyais le post, j'avais l'intuition d'une réponse, confirmée depuis par une lecture (anglaise) expliquant qu'en supprimant le Range trouvé par FIND, la référence rCel ayant disparu, la recherche s'avère impossible à poursuivre.

If CInt(rCel.Offset(0, 2).Value) > iLevel Then

If rCel.Row < 2 + CInt(Cells(1, iCol - 2)) Then Cells(1, rCel.Column + 3) = "!"

rCel.Resize(1, 4).Delete shift:=xlUp

End If

Set rCel = UsedRange.FindNext(rCel)

Depuis, je cherche un moyen de contourner ce truc...

A+

Ach, c'était cela la cause !! J'ai toujours eu un peu de mal avec find et je ne connaissais même pas findnext !

De mon côté, comme j'ai travaillé avec dico dans lequel j'emmenais tous les choix, il m'a suffi de faire un replace du choix moins important par "". Je pense que ton algorithme est bon même meilleur que le mien, il faudrait juste investir dans dico, que je n'avais jamais utilisé de façon aussi extensive dans un projet.

Bonjour tout le monde,

grand merci pour votre aide et vos commentaires.

Suite à ma lecture d'hier, expliquant que l'effacement du dernier Range de la recherche détruisait ipso facto la référence de FINDNEXT, j'avais effectivement d'abord tenté l'approche de Theze du tableau contenant les références des cellules concernées avant que Jean-Eric ne me donne la (toute) bonne piste.

En avançant, je suis arrivé à la solution, confirmée depuis par Eriiic et H2SO4, d'entamer la recherche par un Find( AFTER...), histoire de maîtriser le trajet de FINDNEXT.

            Set rCells = Cells(1, Columns.Count)
            iLevel = Cells(x, iCol + 2)
            Set rCel = UsedRange.Find(Cells(x, iCol), after:=Range("A1"), lookat:=xlWhole)
            If Not rCel Is Nothing Then
                sAdr = rCel.Address
                Do
                    If rCel.Offset(0, 2) > iLevel Then
                        If rCel.Row < 2 + iRow And Cells(3, rCel.Column) <> "" Then Cells(1, rCel.Column + 3) = ".."
                        Set rCells = Union(rCells, rCel.Resize(1, 4))
                    End If
                    Set rCel = UsedRange.FindNext(rCel)
                Loop While Not rCel Is Nothing And rCel.Address <> sAdr
                rCells.Delete shift:=xlUp
            End If

Comme disait l'autre, bonne réponse collective! Vous aurez tous un bon point!

Sans vouloir en faire de trop, je suis très heureux que de grosses pointures se soient penchés sur ma demande.

Grand merci à tous!

A+

Accessoirement je te conseille de toujours fixer le paramètre LookIn:= également.

Il n'a pas de valeur par défaut et dépend du dernier choix fait par l'utilisateur dans Ctrl+f (Rechercher/Remplacer)

xlFormulas recherche dans la propriété .Formula (à privilégier pour les saisies)

xlValues effectue sa recherche dans la propriété .Text et non .Value (valeur affichée qui dépend du format et de la largeur de la colonne, attention au piège !)

eric

Bonjour à tous,

Bonjour Eric, tu dis :

xlValues effectue sa recherche dans la propriété .Text et non .Value (valeur affichée qui dépend du format et de la largeur de la colonne, attention au piège !)

Là, je ne serai pas autant affirmatif que toi car avec le code ci-dessous, si la recherche se fait sur la propriété "Text", la date devrait être trouvée avec une date de type String et chez moi, ce n'est pas le cas :

Sub Test()

    Dim Plage As Range
    Dim Cel As Range
    Dim LaDate As String
    Dim La2emeDate As Date
    Dim La3emeDate As Long
    Dim F As String

    LaDate = "25/10/2019"
    La2emeDate = CDate("25/10/2019")
    La3emeDate = CLng(CDate("25/10/2019"))

    Set Plage = Range("A1:A31")

    'teste si la concordance est vrai entre la date en String et la valeur en A25 (qui est le 25/10/2019)
    MsgBox "La date se trouve en A25 et la concordance est " & (Plage(25, 1).Text = LaDate)

    'type des propriétés pour la première cellule de la plage (qui sont les mêmes pour toutes)
    MsgBox "Type de valeur dans les propriétés :" & _
           vbCrLf & _
           "Value : " & TypeName(Plage(1, 1).Value) & _
           vbCrLf & _
           "Text : " & TypeName(Plage(1, 1).Text) & _
           vbCrLf & _
           "Value2 : " & TypeName(Plage(1, 1).Value2)

    'ici, la date n'est pas trouvée !
    Set Cel = Plage.Find(LaDate, , xlValues, xlWhole)
    If Not Cel Is Nothing Then MsgBox "La date typée 'String' se trouve en " & Cel.Address(0, 0)

    Set Cel = Plage.Find(La2emeDate, , xlValues, xlWhole)
    If Not Cel Is Nothing Then MsgBox "La date typée 'Date' se trouve en " & Cel.Address(0, 0)

    'ici, le format de la plage est passé en Standard puyis rétabli après recherche
    F = Plage.NumberFormat
    Plage.NumberFormat = "General"
    Set Cel = Plage.Find(La3emeDate, , xlValues, xlWhole)
    If Not Cel Is Nothing Then MsgBox "La date typée 'Long' se trouve en " & Cel.Address(0, 0)
    Plage.NumberFormat = F

End Sub

A1:A31 contient les dates du mois d'octobre

Peux-tu me montrer ce qui te fait dire que c'est sur la propriété "Text" que s'effectue la recherche car je n'ai aucune certitude et j'ai toujours cru que c'était sur la propriété "Value" ?

Bonjour Theze,

C'est bien pour ça que c'est le b...l .find avec les dates. On a intérêt à connaitre parfaitement le contexte et être sûr qu'il immuable.

Je prend juste ton 1er test

MsgBox "La date se trouve en A25 et la concordance est " & (Plage(25, 1).Text = LaDate)

qui retourne effectivement VRAI. Enfin chez moi, à te lire j'ai l'impression que c'est FAUX pour toi (?)

Maintenant je met la colonne au format mm/aa, j'ai le droit et ça ne change pas la date.

Plus rien n'est trouvé, même avec la recherche avec Clng(la_date)

Pour embrouiller encore plus prenons le test :

Set Cel = Plage.Find(La2emeDate, , xlValues, xlWhole)

on pourrait se dire ah, c'est bon, si les dates sont au format jj/mm/aaaa je peux rechercher avec une vraie date.

Et bien non.

Ca dépend du format de date courte choisi dans le panneau de config Région et langue (si tu as FAUX au 1er test, la réponse est peut-être là).

Si j'ai choisi jj/mm/aa et mis un format personnalisé jj/mm/aaaa il ne trouve plus.

C'est un sac d'embrouilles sans fin.

Pour moi ils ont donné la réalisation de .find au stagiaire là depuis 3 jours et qui s'est mélangé entre .Value et .Text.

Pour t'en persuader je te propose un test plus simple qu'avec les dates.

Juste trouver 12345678 mis de A2 à E2.

Résultat : .find n'en trouve qu'un seul sur les 5

Par contre si je recherche avec xlFormulas (qui est égal à .Value pour les saisies) je trouve bien 5 fois 12345678

Pour rechercher sur .Value guère d'autre possibilité que Equiv() qui sera correct pour saisies et formules, c'est ce que j'utilise pour les dates dès le moindre doute.

eric

5test-find.xlsm (17.07 Ko)

Bonjour Eric,

qui retourne effectivement VRAI. Enfin chez moi, à te lire j'ai l'impression que c'est FAUX pour toi (?)

Il me retourne Vrai chez moi mais si la recherche est faite sur Text, pourquoi il ne me la trouve pas ?

Par contre, il me retourne Faux au boulot avec la même version d'Excel !!! Et en plus, le test sur le typage chez moi donne :

Value = Date, Text = String et Value2 = Double et ici, trois fois String !!!

Décidément, les voies d'Excel sont impénétrable

Bonjour theze,

Il me retourne Vrai chez moi mais si la recherche est faite sur Text, pourquoi il ne me la trouve pas ?

Chez moi il la trouve bien avec .Find(LaDate d'où mon incompréhension.

Et si je met en format personnalisé jj/mm/aa il faut que je change LaDate = "25/10/19" pour qu'il la retrouve.

Ce qui semble aller dans le sens de .Text

Mais bon, le test sur 12345678 est plus simple à appréhender que ce bourbier infâme avec les dates

Value = Date, Text = String et Value2 = Double et ici, trois fois String !!!

Ca ne serait pas toi j'aurais du mal à le croire.

A ce niveau, trouver une explication va être difficile

Quelle version par curiosité ?

eric

Hello Eric !

Je suis sous Excel 2007 32 bits sur les deux PC !

J'ai fais ton test avec xlValues et effectivement sur les deux PC il ne me trouve que la première occurrence alors qu'avec xlFormulas, il trouve les 5

Maintenant, sur mon PC perso, TypeName() me retourne ici aussi String pour les trois alors que hier soir les types étaient différents

A ce niveau, trouver une explication va être difficile

Effectivement mais à ce stade, je ne vais pas me rendre malade pour ça

Bonjour,

j'espère que ce n'est pas contagieux par les forums ton truc

Dans le doute je vais mettre une capote à ma clé wifi...

eric

j'espère que ce n'est pas contagieux par les forums ton truc

Dans le doute je vais mettre une capote à ma clé wifi...

J'ai tout supprimé pour que ça ne se propage pas

Rechercher des sujets similaires à "encore find"