VBA - Supprimer aléatoirement un nombre défini de ligne

Bonjour,

Je dois créer un échantillon aléatoire dans un fichier qui contient x ligne.

Je souhaiterais garder uniquement 20 lignes de ce fichier et cela de façon aléatoire.

J'ai cru comprendre que je pouvais utiliser la fonction While de VBA mais je ne vois pas comment...

Connaitriez vous un code qui puisse me permettre de faire cela ?

Merci d'avance pour votre aide.

Bonjour Pauline

Tes données en Feuil1 ton choix de lignes en feuil2, essaie cela:

Sub LignesAuHasard()
    DLig = Worksheets("Feuil1").Range("A65536").End(xlUp).Row
    For i = 1 To 20
        Randomize
        x = Int(Rnd * DLig + 1)
        Worksheets("Feuil1").Rows(x).Copy Destination:=Worksheets("Feuil2").Rows(i)
    Next
End Sub

Dis moi

Bonsoir Patty5046

Ca fonctionne merci beaucoup.

Cependant je ne peux pas avoir de doublon dans mon échantillon et là c'est le cas. Pourrais tu me dire comment je peux faire pour intégrer dans le code d'avoir un choix aléatoire sans doublon ?

(C'était pour cela que je pensais supprimer et pas copier dans une autre feuille, parce que normalement la fonction ne peux pas supprimer quelque chose 2 fois ?)

bonsoir,

une autre proposition (sans doublons)

Sub aargh()
    Set ws = Sheets.Add
    With Sheets("sheet1")
        dl = .Cells(Rows.Count, 1).End(xlUp).Row
        .Columns(1).Insert shift:=xlToRight
        For i = 1 To 20
            Do
                q = aleatoire(1, dl)
            Loop Until .Cells(q, 1) = ""
            .Cells(q, 1) = 1
        Next i
        .Rows("1:" & dl).Sort key1:=.Cells(1, 1), Order1:=xlDescending, Header:=xlNo
        .Columns(1).Delete shift:=xlLeft
        .Rows("1:20").Copy ws.Cells(1, 1)
    End With
End Sub

Function aleatoire(borne_inférieure, borne_supérieure)
    aleatoire = Int(Rnd() * (borne_supérieure - borne_inférieure + 1)) + borne_inférieure
End Function

Bonjour h2so4,

J'ai lancé le code. J'ai laissé en running pendant 15 min mais mon fichier est passé en "Not responding".

J'ai l'impression qu'une boucle était a l'infini. J'ai donc fermé le fichier et réouvert et ca m'a créer une nouvelle feuille nommé "Sheet1" et il y a un 1 dans la cellule A1

Bonsoir,

un test inspiré de la solution de Patty5046:

Sub LignesAuHasard()
Dim Dlig As Long, lig As Long
Dim tailleEchantillon As Integer, nbValeurs As Integer, ligDep As Integer
Dim tabLignes As Variant

'initialisations
nbValeurs = 0
ligDep = 2 'ligne 1 = en-têtes
Dlig = Worksheets("Feuil1").Range("A" & Rows.Count).End(xlUp).Row
tailleEchantillon = 20
ReDim tabLignes(1 To tailleEchantillon)

If Dlig - ligDep + 1 < tailleEchantillon Then
    MsgBox "Il n'y a pas assez de valeurs pour créer un échantillon de cette taille", vbInformation, "Information"
Else
    While nbValeurs < tailleEchantillon
        Randomize
        lig = Int(Rnd * (Dlig - (ligDep - 1)) + 1 + ligDep - 1)

        If Not estDoublon(lig, tabLignes) Then
            nbValeurs = nbValeurs + 1
            Worksheets("Feuil1").Rows(lig).Copy Worksheets("Feuil2").Rows(ligDep + nbValeurs - 1)
            tabLignes(nbValeurs) = lig
        End If
    Wend
End If
End Sub

Function estDoublon(ByVal valeur, ByVal tableau) As Boolean 'false par défaut
If IsArray(tableau) Then
    For i = LBound(tableau, 1) To UBound(tableau, 1)
        If valeur = tableau(i) Then
            estDoublon = True
            Exit For
        End If
    Next i
End If
End Function

Bon c'est pas la solution la plus optimale car il faudrait sûrement plutôt avoir une collection qu'on vide au fur et à mesure mais bon...

RE

Bonjour à tous...j'avais zappé que tu voulais supprimer des lignes:

Sub SupprimerLignesAuHasard()
    DLIg = Worksheets("Feuil1").Range("A65536").End(xlUp).Row
    For i = 1 To 20
        Randomize
        x = Int(Rnd * DLIg + 1)
        Worksheets("Feuil1").Rows(x).EntireRow.Delete
        DLIg = DLIg - 1
    Next
End Sub

Bonne soirée à tous

Du coup j'ai modifié un autre code que j'ai trouvé sur un autre site et ca fonctionne :

Sub Sampling()
Dim Plage As Range, I As Integer, DerLigne As Integer
DerLigne = Range("A" & Rows.Count).End(xlUp).Row
I = Rnd() * DerLigne + 1
Set Plage = Range("A" & I)
While Plage.Count < DerLigne - 20
I = Rnd() * DerLigne
Set Plage = Union(Plage, Range("A" & I))
Wend
Plage.EntireRow.Delete
End Sub

N'hésitez pas à me dire s'il y a une erreur ou si on peut l'améliorer.

@Ausecour ton code fonctionne super merci beaucoup !

@Patty5046 ton code ne me supprime que 20 lignes au lieu de m'en conserver que 20.

Merci encore pour votre aide.

Je vous souhaite une excellent soirée.

Du coup j'ai modifié un autre code que j'ai trouvé sur un autre site et ca fonctionne :

Sub Sampling()
Dim Plage As Range, I As Integer, DerLigne As Integer
DerLigne = Range("A" & Rows.Count).End(xlUp).Row
I = Rnd() * DerLigne + 1
Set Plage = Range("A" & I)
While Plage.Count < DerLigne - 20
I = Rnd() * DerLigne
Set Plage = Union(Plage, Range("A" & I))
Wend
Plage.EntireRow.Delete
End Sub

N'hésitez pas à me dire s'il y a une erreur ou si on peut l'améliorer.

@Ausecour ton code fonctionne super merci beaucoup !

@Patty5046 ton code ne me supprime que 20 lignes au lieu de m'en conserver que 20.

Merci encore pour votre aide.

Je vous souhaite une excellent soirée.

Techniquement je dirais qu'il est améliorable oui, pour déjà une raison, plutôt que de chercher à supprimer plein de lignes aléatoirement jusqu'à ce qu'il ne reste que le nombre désiré, il peut-être plus rapide de sélectionner un certains nombre de lignes, en plus j'ai l'impression que ton code gère aussi mal les doublons que celui que j'ai fait, il va simplement reboucler encore et encore si les lignes sur lesquelles tu tombes sont déjà présentes, donc j'aurais tendance à dire que c'est du temps perdu niveau calcul.

J'ai une préférence pour une autre méthode mais je ne suis pas réellement sûr qu'elle soit plus rapide, je n'ai étrangement jamais fait de tests pour comparer les vitesses d'exécution avec une autre méthode.

Après si pour ton besoin ça fonctionne suffisamment vite et bien, pas trop besoin de l'améliorer.

Ah et je viens de trouver une petite erreur:

tu mets à la ligne 4:

I = Rnd() * DerLigne + 1

puis ça à la ligne 7:

I = Rnd() * DerLigne

Après ce n'est pas quelque chose qui ne va pas faire fonctionner ton code, mais je ne déclare jamais sur la même ligne des variables de type différent, et j'utilise une méthode de nommage légèrement différente de la tienne, le Camel Case, et je ne mets une première lettre majuscule que quand il s'agit d'objet (Range par exemple), pas de simples variables comme un Integer.

Bonsoir à tous

Sub SupprimerLignesAuHasard()
    DLig = Worksheets("Feuil1").Range("A65536").End(xlUp).Row
    Application.ScreenUpdating = False
    For i = 1 To DLig - 20
        Randomize
        x = Int(Rnd * DLig + 1)
        Worksheets("Feuil1").Rows(x).EntireRow.Delete
        DLig = DLig - 1
    Next
    Application.ScreenUpdating = True

End Sub

Voilà enfin ... environ 30 secondes

bonsoir,

heureux pour toi que tu aies trouvé une solution.

J'ai lancé le code. J'ai laissé en running pendant 15 min mais mon fichier est passé en "Not responding".

En fait il faut remplacer "sheet1" par le nom de ta feuille qui contient tes données à sélectionner. la macro créera une nouvelle feuille avec les 20 lignes sélectionnées.

la macro se base sur la première colonne pour déterminer le nombre de lignes de ton fichier. s'il y en a moins de 20, cas que je n'avais pas prévu, tu as en effet un boucle sans fin.

Rechercher des sujets similaires à "vba supprimer aleatoirement nombre defini ligne"