XL 2019 Problème de Tri de nombres avec des points

  • Initiateur de la discussion Initiateur de la discussion Titof06
  • Date de début Date de début

Boostez vos compétences Excel avec notre communauté !

Rejoignez Excel Downloads, le rendez-vous des passionnés où l'entraide fait la force. Apprenez, échangez, progressez – et tout ça gratuitement ! 👉 Inscrivez-vous maintenant !

Titof06

XLDnaute Occasionnel
Bonjour,

Je souhaite faire un tri, dans mon cas, de familles de produit, qui contient 1 ou 2 points entre les nombres.

Dans le fichier joint, J'ai la colonne "D" à trier.
Lorsque je trie, il s'affiche comme vous le voyez.
Il faudrait que je puisse le trier comme le début de la Colonne "E".

Idem avec les Colonnes "G" et "H".

En fait je cherche à faire un tri avec une priorité numérique pour chacun des nombres à gauche et après le ".".

Je vous remercie et vous souhaite une agréable journée,

Titof06
 

Pièces jointes

@patricktoulon
je ne comprend pas ta remarque...
sur le fichier fourni, en colonne D: il y a bien des numéros de chapitre différents et des sous chapitre
1.10 ==> chapitre 1 . sous chapitre 10

et rapidement, je vois jusqu'au chapitre 95, sous chapitre 20
la solution PQ (que j'ai modifiée ici) a l'air de bien donner le résultat trié par chapitre / souschapitre

et en écrivant, je crois voir le souci..
selon que les données sources sont au format texte ou nombre la première donnée passe de 1.10 à 1.1 et n'est donc pas placée au meme endroit par le tri
 

Pièces jointes

Bonjour à tous,

Pour ceux qui aiment Power Query, une autre solution.

PowerQuery:
= ((x)=> Table.FromList(List.Sort(x, List.Transform({0..List.Max(List.Transform(x, List.Count))-1}, (y)=> {each Number.From(_{y} ?),0})), each {Text.Combine(_,".")}, {"Trié"}))
(List.Distinct(Table.ToList(Excel.CurrentWorkbook(){[Name="Table1"]}[Content], each List.RemoveItems(Text.SplitAny(Text.From(_{0}),"."), {""}))))

Bonne journée.
 
@patricktoulon
je ne comprend pas ta remarque...
sur le fichier fourni, en colonne D: il y a bien des numéros de chapitre différents et des sous chapitre
1.10 ==> chapitre 1 . sous chapitre 10

et rapidement, je vois jusqu'au chapitre 95, sous chapitre 20
la solution PQ (que j'ai modifiée ici) a l'air de bien donner le résultat trié par chapitre / souschapitre

et en écrivant, je crois voir le souci..
selon que les données sources sont au format texte ou nombre la première donnée passe de 1.10 à 1.1 et n'est donc pas placée au meme endroit par le tri
non je veux dire que dans l'exemple de départ il y avait
x.xx.xx
x.x
et maintenant il y en a plus
dans une même colonne
donc si c'est toujours d'actualité alors tes deux versions plantes sur ce detail et plus précisément sur les chaines à un seul point
d’où ma remarque du début; passer par un mask de lettre qui va faire fi du nombre de points

le l'ai fait tout a l'heure avec la méthode mask et ça prend le nombre de séparateur que tu veux dans une même colonne en faisant le job

démo
pour l'a démo j'affiche les masks
demo1.gif
 
voici comment je fait
1° je vais créer une matrice de lettre correspondant au in dex de chiffres en utilisant ce que j'ai à dispo c'est a dire les addresse de colonne en l'occurence ici je vais de 1 à 100
ce qui fait que je vais pouvoir traiter des ref du style 99.99.99.99.99etc...etc... à l'infini

la matrice lettre
VB:
'patricktoulon

'matrice de mask
Function Maskletters()
    Dim T(1 To 100)
    For i = 1 To 100: T(i) = Split(Columns(i).Address(0, 0), ":")(0): Next
    Maskletters = T
End Function

ensuite je vais convertir les valeurs du tableau entre les points en lettre
et j'appelle le quicksort à la fin en injectant le tableau converti ET !!! le tableau original
dans le quicksort quand je deplace une ligne du tableau converti (le mask) je deplace les même ligne dans le tableau original
Code:
'patricktoulon'
Sub test()
    tmask = Maskletters
    T = Range("B2:B461").Value
    tconvert = T

    'conversion en mask
    For lig = 1 To UBound(T)
        it = Split(T(lig, 1), ".")
        For i = LBound(it) To UBound(it)
            If it(i) > 0 Then it(i) = tmask(it(i))
        Next
        tconvert(lig, 1) = CStr(Join(it, "_"))
    Next

'tri du tableau de mask (Test injecté aussi pour que les lignes soient déplacées en même temps)
    tbl = TableOrderByChooseColumn(tconvert, T)

    'juste pour voir les mask(facultatif)
    [D1] = "mask"
    [D2].Resize(UBound(T)) = tbl

    'affichage de la colonne triée
    [E1] = "Trié"
    [E2].Resize(UBound(T)) = T
 [E2].Resize(UBound(T)).Replace ",", "."
End Sub

ma fonction quicksort by colonne et (croissant/décroissant) que j'utilise partout
elle peut être simplifié pour la ramener a un tri croissant simplement
perso je préfère la garder comme ça elle va partout
pour l'occasion j'ai ajouter le 2d tableaux
VB:
Function TableOrderByChooseColumn(a, T, Optional gauc = -1, Optional droi = -1, Optional sens As Long = 0, Optional Colonne As Long = 1) ' Quick sort
    'patricktoulon
    Dim ref, g&, d&, temp1, temp2, C&
    If TypeName(a) = "Range" Then a = a.Value
    droi = IIf(droi = -1, UBound(a), droi): gauc = IIf(gauc = -1, LBound(a), gauc)
    ref = a((gauc + droi) \ 2, Colonne)
    g = gauc: d = droi
    Do
        Select Case sens 'en fonction du sens de tri choisi
            Case 0
                ' Pour un tri croissant
                Do While a(g, Colonne) < ref: g = g + 1: Loop
                Do While ref < a(d, Colonne): d = d - 1: Loop
            Case 1
                ' Pour un tri décroissant
                Do While a(g, Colonne) > ref: g = g + 1: Loop
                Do While ref > a(d, Colonne): d = d - 1: Loop
        End Select
        If g <= d Then
            'récupération des deux lignes entieres du tableau (a)
            temp1 = Application.Index(a, g, 0): temp2 = Application.Index(a, d, 0)
            tempb1 = Application.Index(T, g, 0): tempb2 = Application.Index(T, d, 0)
            'transfert d'une ligne a l'autre vice et versa
            For C = 1 To UBound(temp1)
                a(g, C) = temp2(C): a(d, C) = temp1(C)
                T(g, C) = tempb2(C): T(d, C) = tempb1(C)

            Next
            g = g + 1: d = d - 1
        End If
    Loop While g <= d
    If g < droi Then X = TableOrderByChooseColumn(a, T, g, droi, sens, Colonne)
    If gauc < d Then X = TableOrderByChooseColumn(a, T, gauc, d, sens, Colonne)
    TableOrderByChooseColumn = a
End Function
 
@patricktoulon
je ne comprend pas ta remarque...
sur le fichier fourni, en colonne D: il y a bien des numéros de chapitre différents et des sous chapitre
1.10 ==> chapitre 1 . sous chapitre 10

et rapidement, je vois jusqu'au chapitre 95, sous chapitre 20
la solution PQ (que j'ai modifiée ici) a l'air de bien donner le résultat trié par chapitre / souschapitre

et en écrivant, je crois voir le souci..
selon que les données sources sont au format texte ou nombre la première donnée passe de 1.10 à 1.1 et n'est donc pas placée au meme endroit par le tri
Re-Bonjour vgendron et @patricktoulon,

Pour ma part le tri qui sort, me convient.
Dans mon cas, il est juste de faire 1.8 1.9 1.10 1.11 1.12 etc.

Je vous remercie et vous souhaite une agréable journée,

Titof06
 

voici comment je fait
1° je vais créer une matrice de lettre correspondant au in dex de chiffres en utilisant ce que j'ai à dispo c'est a dire les addresse de colonne en l'occurence ici je vais de 1 à 100
ce qui fait que je vais pouvoir traiter des ref du style 99.99.99.99.99etc...etc... à l'infini

la matrice lettre
VB:
'patricktoulon

'matrice de mask
Function Maskletters()
    Dim T(1 To 100)
    For i = 1 To 100: T(i) = Split(Columns(i).Address(0, 0), ":")(0): Next
    Maskletters = T
End Function

ensuite je vais convertir les valeurs du tableau entre les points en lettre
et j'appelle le quicksort à la fin en injectant le tableau converti ET !!! le tableau original
dans le quicksort quand je deplace une ligne du tableau converti (le mask) je deplace les même ligne dans le tableau original
Code:
'patricktoulon'
Sub test()
    tmask = Maskletters
    T = Range("B2:B461").Value
    tconvert = T

    'conversion en mask
    For lig = 1 To UBound(T)
        it = Split(T(lig, 1), ".")
        For i = LBound(it) To UBound(it)
            If it(i) > 0 Then it(i) = tmask(it(i))
        Next
        tconvert(lig, 1) = CStr(Join(it, "_"))
    Next

'tri du tableau de mask (Test injecté aussi pour que les lignes soient déplacées en même temps)
    tbl = TableOrderByChooseColumn(tconvert, T)

    'juste pour voir les mask(facultatif)
    [D1] = "mask"
    [D2].Resize(UBound(T)) = tbl

    'affichage de la colonne triée
    [E1] = "Trié"
    [E2].Resize(UBound(T)) = T
 [E2].Resize(UBound(T)).Replace ",", "."
End Sub

ma fonction quicksort by colonne et (croissant/décroissant) que j'utilise partout
elle peut être simplifié pour la ramener a un tri croissant simplement
perso je préfère la garder comme ça elle va partout
pour l'occasion j'ai ajouter le 2d tableaux
VB:
Function TableOrderByChooseColumn(a, T, Optional gauc = -1, Optional droi = -1, Optional sens As Long = 0, Optional Colonne As Long = 1) ' Quick sort
    'patricktoulon
    Dim ref, g&, d&, temp1, temp2, C&
    If TypeName(a) = "Range" Then a = a.Value
    droi = IIf(droi = -1, UBound(a), droi): gauc = IIf(gauc = -1, LBound(a), gauc)
    ref = a((gauc + droi) \ 2, Colonne)
    g = gauc: d = droi
    Do
        Select Case sens 'en fonction du sens de tri choisi
            Case 0
                ' Pour un tri croissant
                Do While a(g, Colonne) < ref: g = g + 1: Loop
                Do While ref < a(d, Colonne): d = d - 1: Loop
            Case 1
                ' Pour un tri décroissant
                Do While a(g, Colonne) > ref: g = g + 1: Loop
                Do While ref > a(d, Colonne): d = d - 1: Loop
        End Select
        If g <= d Then
            'récupération des deux lignes entieres du tableau (a)
            temp1 = Application.Index(a, g, 0): temp2 = Application.Index(a, d, 0)
            tempb1 = Application.Index(T, g, 0): tempb2 = Application.Index(T, d, 0)
            'transfert d'une ligne a l'autre vice et versa
            For C = 1 To UBound(temp1)
                a(g, C) = temp2(C): a(d, C) = temp1(C)
                T(g, C) = tempb2(C): T(d, C) = tempb1(C)

            Next
            g = g + 1: d = d - 1
        End If
    Loop While g <= d
    If g < droi Then X = TableOrderByChooseColumn(a, T, g, droi, sens, Colonne)
    If gauc < d Then X = TableOrderByChooseColumn(a, T, gauc, d, sens, Colonne)
    TableOrderByChooseColumn = a
End Function


j'ai pas testé ta solution, mais as tu noté que notre ami a omis de dire que la décomposition en chapitre peut contenir aussi des lettres..
j'ai vu un 20.5.Z (lettre Z) (nombres non contractuels)
ainsi qu'un 20;60;32 (les points sont remplacés par un point virgule)
 




j'ai pas testé ta solution, mais as tu noté que notre ami a omis de dire que la décomposition en chapitre peut contenir aussi des lettres..
j'ai vu un 20.5.Z (lettre Z) (nombres non contractuels)
ainsi qu'un 20;60;32 (les points sont remplacés par un point virgule)
Re-Bonjour vgendron et @patricktoulon,

Oui, désolé, pour la lettre "Z".
Cela ne doit pas être trié, elle ne devrait pas apparaître, désolé, c'est ma faute.
Idem, il n'y a pas de ";", ceci est une erreur de ma part dans un fâcheux copier-coller.

Je vous remercie pour tous vos efforts pour moi, et vous souhaite une agréable journée,

Titof06
 
pour le fun, j'ai modifié la macro pour qu'elle puisse trier la colonne A (sous réserve d'avoir supprimé les lignes contenant des lettres et remplacé les ; par des .
le chapitre 1 devient 1.0.0
1.10 devient 1.10.0

VB:
Sub TriPoint()
Dim TabData() As Variant
Dim TabToTri() As Variant

Set plage = Application.InputBox("Cliquez dans la colonne à trier", Type:=8) 'demande à l'utilisateur de cliquer dans la colonne à trier==> !! AUCUN controle sur la validité de la selection

    With ActiveSheet 'avec la feuille active
        Col = plage.Column 'colonne sélectionné
        LastLine = .Cells(.Rows.Count, Col).End(xlUp).Row 'dernière ligne non vide de la colonne selectionnée
        TabVal = .Cells(2, Col).Resize(LastLine - 1, 1).Value 'on met juste la colonne dans un tableau vba
        For i = LBound(TabVal, 1) To UBound(TabVal, 1)  'pour chaque ligne
            nbpoint = WorksheetFunction.Max(nbpoint, Len(TabVal(i, 1)) - Len(WorksheetFunction.Substitute(TabVal(i, 1), ".", ""))) 'on compte le nombre de point, et on met à jour le nombre "max"
        Next i
        
        TabData = .Cells(2, Col).Resize(LastLine - 1, nbpoint + 2).Value 'on place la colonne à trier dans un tableau + nb de colonnes fonction du nombre de point (pour les calculs)
    End With
    
    For i = LBound(TabData, 1) To UBound(TabData, 1)  'pour chaque ligne du tableau
        nb = UBound(Split(TabData(i, 1), ".")) 'nb de points à la ligne
        For j = 0 To nb 'on split les valeurs
            TabData(i, j + 2) = CInt(Split(TabData(i, 1), ".")(j))
        Next j
        For j = nb + 1 To nbpoint 'pour le reste, on met 0
            TabData(i, j + 2) = 0
        Next j
    Next i
    'ActiveSheet.Range("F2").Resize(UBound(TabData, 1), UBound(TabData, 2)) = TabData
    
    ReDim ColToTri(nbpoint) As Long 'définition d'un array contenant les colonnes à trier
    For i = 0 To nbpoint
        ColToTri(i) = i + 2 'la colonne 1 contient les données initiales: ne servent pas pour le tri
    Next i

    Call TriTabMultX(TabData, ColToTri) 'on appelle la macro de tri

    'ActiveSheet.Range("I2").Resize(UBound(TabData, 1), UBound(TabData, 2)) = TabData
    
    'on reconstruit le numéro de chapitre selon le contenu des colonnes "splitées"
    For i = LBound(TabData, 1) To UBound(TabData, 1)
        recons = ""
        For j = LBound(TabData, 2) + 1 To UBound(TabData, 2)
            recons = recons & "." & TabData(i, j)
        Next j
        TabData(i, 1) = Mid(recons, 2, Len(recons) - 1)
    Next i
    
    ActiveSheet.Range("F2").Resize(UBound(TabData, 1), 1).NumberFormat = "@"
    ActiveSheet.Range("F2").Resize(UBound(TabData, 1), 1) = TabData
End Sub
 
et si on ne veut pas des .0
Code:
For i = LBound(TabData, 1) To UBound(TabData, 1)
        recons = ""
        For j = LBound(TabData, 2) + 1 To UBound(TabData, 2)
            recons = recons & "." & TabData(i, j)
        Next j
        TabData(i, 1) = WorksheetFunction.Substitute(Mid(recons, 2, Len(recons) - 1), ".0", "")
    Next i
 
Re,
Ci-joint une version avec Power Query pour codes avec 1 ou 2 points
Il suffit de faire un clic droit dans les colonnes "Familles triées" et de cliquer sur actualiser.
Pas de macro, et conservation de tes points
À bientôt
Salut @AtTheOne, j'ai inséré la valeur "1.21" en colonne A ( cellule standard ) et j'ai fait "Actualiser",
PQ semble l'avoir converti en nombre non exploitable sur mon Excel .
1746088223670.png
DecimalSeparator =>.<=
ThousandsSeparator => <=
UseSystemSeparators =>Faux<=

 
- Navigue sans publicité
- Accède à Cléa, notre assistante IA experte Excel... et pas que...
- Profite de fonctionnalités exclusives
Ton soutien permet à Excel Downloads de rester 100% gratuit et de continuer à rassembler les passionnés d'Excel.
Je deviens Supporter XLD

Discussions similaires

  • Question Question
XL 2021 listbox
Réponses
18
Affichages
283
Réponses
9
Affichages
552
Retour