VBA [Ajout de feuilles variant selon le nombre de combinaisons.]

arnaud95

XLDnaute Nouveau
Bonjour à tous.En fait j'ai trouvé sur internet une macro qui trouve l'ensemble des combinaisons, moi perso je suis débutant en VBA et je n'y connais pas grand chose. Le problème que j'ai c'est qu'à partir d'un moment le nombre de combinaisons devient trop élevé pour etre affiché sur une page et donc je n'ai que les resultats partiels. Ce que je souhaiterai c'est qu'excel ajoute une nouvelle feuille à chaque fois que la precedente est terminée et finalement que je puisse avoir tous les resultats sur l'enemble des feuilles.
Ma macro est la suivante.
Je vous mets la macro en pièce jointe si vous souhaitez la tester et je la mets également ci dessous.

'Dans l'onglet combinaisons.
'1. En A1, écrire c ou p ; (Combinaison ou Permutation)
'2. En A2, écrire la valeur de p ;(p tirés parmi N)
'3. Sous A2, écrire la liste des N éléments ;
'4. Sélectionner A1 et activer la procédure.

'Exemple:
'A1 c
'A2 3
'A3 1
'A4 2
'A5 Excel
'A6 4
'A7 *
'A8 6
'
'La procédure donne alors la liste de toutes les combinaisons
'possibles de 3 éléments choisis parmi 6.

Option Explicit

Dim vAllItems As Variant
Dim Buffer() As String
Dim BufferPtr As Long
Dim Results As Worksheet





Sub ListPermutations1()
Worksheets("combinaisons").Select
Range("A1").Select
Dim Rng As Range
Dim PopSize As Integer
Dim SetSize As Integer
Dim Which As String
Dim N As Double
Dim message As Integer
Dim nom As String
Dim sh As Worksheet, trouvé As Boolean
trouvé = False

message = InputBox("nombre d'éléments p?", "Combinaison des élements p parmi N", 3)
Range("A2") = message
Const BufferSize As Long = 65535

Set Rng = Selection.Columns(1).Cells
If Rng.Cells.Count = 1 Then
Set Rng = Range(Rng, Rng.End(xlDown))
End If

PopSize = Rng.Cells.Count - 2
If PopSize < 2 Then GoTo DataError

SetSize = Rng.Cells(2).Value
If SetSize > PopSize Then GoTo DataError

Which = UCase$(Rng.Cells(1).Value)
Select Case Which
Case "C"
N = Application.WorksheetFunction.Combin(PopSize, SetSize)
Case "P"
N = Application.WorksheetFunction.Permut(PopSize, SetSize)
Case Else
GoTo DataError
End Select
If N > Cells.Count Then GoTo DataError

Application.ScreenUpdating = False

nom = "résultats"
Set Results = Worksheets.Add
On Error Resume Next
Application.DisplayAlerts = False
Sheets("résultats").Delete
Application.DisplayAlerts = True
Results.Name = nom

vAllItems = Rng.Offset(2, 0).Resize(PopSize).Value
ReDim Buffer(1 To BufferSize) As String
BufferPtr = 0

If Which = "C" Then
AddCombination PopSize, SetSize
Else
AddPermutation PopSize, SetSize
End If
vAllItems = 0

Application.ScreenUpdating = True
Exit Sub

DataError:
If N = 0 Then
Which = "Enter your data in a vertical range of at least 4 cells. " _
& String$(2, 10) _
& "Top cell must contain the letter C or P, 2nd cell is the number" _
& "of items in a subset, the cells below are the values from which" _
& "the subset is to be chosen."
Else
Which = "This requires " & Format$(N, "#,##0") & _
" cells, more than are available on the worksheet!"
End If
MsgBox Which, vbOKOnly, "DATA ERROR"
Exit Sub
End Sub

Private Sub AddPermutation(Optional PopSize As Integer = 0, _
Optional SetSize As Integer = 0, _
Optional NextMember As Integer = 0)

Static iPopSize As Integer
Static iSetSize As Integer
Static SetMembers() As Integer
Static Used() As Integer
Dim i As Integer

If PopSize <> 0 Then
iPopSize = PopSize
iSetSize = SetSize
ReDim SetMembers(1 To iSetSize) As Integer
ReDim Used(1 To iPopSize) As Integer
NextMember = 1
End If

For i = 1 To iPopSize
If Used(i) = 0 Then
SetMembers(NextMember) = i
If NextMember <> iSetSize Then
Used(i) = True
AddPermutation , , NextMember + 1
Used(i) = False
Else
SavePermutation SetMembers()
End If
End If
Next i

If NextMember = 1 Then
SavePermutation SetMembers(), True
Erase SetMembers
Erase Used
End If

End Sub 'AddPermutation

Private Sub AddCombination(Optional PopSize As Integer = 0, _
Optional SetSize As Integer = 0, _
Optional NextMember As Integer = 0, _
Optional NextItem As Integer = 0)

Static iPopSize As Integer
Static iSetSize As Integer
Static SetMembers() As Integer
Dim i As Integer

If PopSize <> 0 Then
iPopSize = PopSize
iSetSize = SetSize
ReDim SetMembers(1 To iSetSize) As Integer
NextMember = 1
NextItem = 1
End If

For i = NextItem To iPopSize
SetMembers(NextMember) = i
If NextMember <> iSetSize Then
AddCombination , , NextMember + 1, i + 1
Else
SavePermutation SetMembers()
End If
Next i

If NextMember = 1 Then
SavePermutation SetMembers(), True
Erase SetMembers
End If

End Sub 'AddCombination

Private Sub SavePermutation(ItemsChosen() As Integer, _
Optional FlushBuffer As Boolean = False)

Dim i As Integer, sValue As String
Dim j As Integer, w As Long, k As Long
Dim message As Integer
Dim ChaineASeparer


Static RowNum As Long, ColNum As Long

If RowNum = 0 Then RowNum = 1
If ColNum = 0 Then ColNum = 1

If FlushBuffer = True Or BufferPtr = UBound(Buffer()) Then
If BufferPtr > 0 Then
If (RowNum + BufferPtr - 1) > Rows.Count Then
RowNum = 1
ColNum = ColNum + 1
If ColNum > 256 Then Exit Sub
End If


For k = 1 To BufferPtr
ChaineASeparer = Split(Buffer(k), ",")
If (RowNum + BufferPtr - 1) > Rows.Count Then
RowNum = 1
ColNum = Range("A1").End(xlToRight).Column + 1
End If

For w = 0 To UBound(ChaineASeparer)
Results.Cells(RowNum + k - 1, ColNum + w).Value = ChaineASeparer(w)
Next
Next
'Results.Cells(RowNum, ColNum).Resize(BufferPtr, 1).Value _
= Application.WorksheetFunction.Transpose(Buffer())
'RowNum = RowNum + BufferPtr
End If

BufferPtr = 0
If FlushBuffer = True Then
Erase Buffer
RowNum = 0
ColNum = 0
Exit Sub
Else
ReDim Buffer(1 To UBound(Buffer))
End If

End If
'construct the next set
For i = 1 To UBound(ItemsChosen)
j = 1
sValue = sValue & ", " & vAllItems(ItemsChosen(i), 1)
'and save it in the buffer
Next i
BufferPtr = BufferPtr + 1
Buffer(BufferPtr) = Mid$(sValue, 3)
End Sub


Merci beaucoup de votre aide.
 

Pièces jointes

  • TEST COMBI.xls
    36.5 KB · Affichages: 83

Gael

XLDnaute Barbatruc
Re : VBA [Ajout de feuilles variant selon le nombre de combinaisons.]

Bonjour Arnaud,

C'est une procédure que je recommande souvent pour l'avoir déjà utilisé et qui fonctionne très bien.

La procédure change déjà de colonne ce qui te permet d'obtenir tout de même la bagatelle de 65536 lignes *256 colonnes soit 16.700.416 combinaisons différentes et le temps de traitement est assez long de même que la mémoire utilisée.

Si cependant tu souhaites aller plus loin, c'est très simple, il suffit de modifier légèrement le code en remplaçant la ligne suivante:

Code:
If ColNum > 256 Then Exit Sub

par les lignes suivantes:

Code:
If ColNum > 256 Then
        Set Results = Worksheets.Add
        ColNum = 1
        End If

@+

Gael
 

arnaud95

XLDnaute Nouveau
Re : VBA [Ajout de feuilles variant selon le nombre de combinaisons.]

Merci gael, le problème c'est que les résultats sont déjà en colonne, c 'est a dire que si je veux les combinaisons de 3 élément parmi N, j'aurai les colonnes A, B, C remplies ect...de plus j'utiliserai par la suite des vlook up ect...c'est pour çà que je souhaite ajouter des feuilles...
 

Gael

XLDnaute Barbatruc
Re : VBA [Ajout de feuilles variant selon le nombre de combinaisons.]

Bonjour Arnaud,

Je n'ai pas compris exactement ce que tu souhaites mais tu trouveras ci-dessous quelques pistes pour modifier la rocédure et obtenir de remplir exactement les cellules souhaitées:

1 - Tu peux imposer un nombre de colonnes max par feuille en remplacant Rows.count par la valeur désirée:

Code:
If (RowNum + BufferPtr - 1) > 3 Then

2 - Tu peux imposer un nombre de lignes par colonne en changeant les 2 éléments suivants:

Code:
Const BufferSize As Long = 50
Code:
If (RowNum + BufferPtr - 1) > 50 Then

3 - Tu peux choisir la ligne et la colonne de début par exemple pour démarrer en ligne 5 colonne 5:

Code:
  If RowNum = 0 Then RowNum = 5
  If ColNum = 0 Then ColNum = 5
  If FlushBuffer = True Or BufferPtr = UBound(Buffer()) Then
    If BufferPtr > 0 Then
      If (RowNum + BufferPtr - 1) > 55 Then '(Taille buffer + N° de ligne)
        RowNum = 5
        ColNum = ColNum + 1
        If ColNum > 6 Then
        Set Results = Worksheets.Add
        ColNum = 5
        End If
      End If

Pour ma réponse précédente, si tu veux dépasser la limite de 16.777.216 il faut également enlever le test en début de procédure:
Code:
If N > Cells.Count Then GoTo DataError

mais je ne suis pas sûr des conséquences.

Essaye avec ces modifications et n'hésite pas à relancer le problème si tu n'arrives pas à obtenir le résultat souhaité.

@+

Gael
 

Discussions similaires

Réponses
5
Affichages
193

Statistiques des forums

Discussions
312 276
Messages
2 086 711
Membres
103 377
dernier inscrit
fredy45