Macro per combinazioni



  • Macro per combinazioni
    di Segugio (utente non iscritto) data: 25/11/2016 15:19:05

    Buongiorno, sono un appassionato di Excel auto-didatta e da poco tempo utilizzo le macro.
    Vorrei sapere se qualche esperto riesce a risolvermi gentilmente il mio problema:

    Devo creare tutte le combinazioni possibili da 3 gruppi di dati, utilizzandone solo un numero "x" di questi.
    Esempio:

    Colonna A Colonna B Colonna C
    Tizio Tizio1 Tizio2
    Caio Caio1 Caio2
    Sempronio Sempronio1 Sempronio2
    Gino Gino1 Gino2
    Pino Pino1 Pino2
    Lino Lino1 Lino2

    Ora, a me servirebbero le combinazioni senza ripetizioni prendendo, per esempio, 2 nomi dalla colonna A, 2 dalla colonna B e 2 dalla colonna C. Questo numero può essere variabile, quindi anche 3 da A, 5 da B o 2 da C.
    L'ideale sarebbe ottenere i risultati in un foglio nuovo con un nome per ogni cella, una combinazione ogni riga.
    Attualmente ho una macro che fa bene il suo mestiere ma solo su un gruppo, e non su 3.
    Vi ringrazio


     
    Option Explicit
     
     'Written by Myrna Larson - Microsoft Excel MVP
    Dim vAllItems As Variant
    Dim Buffer() As String
    Dim BufferPtr As Long
    Dim Results As Worksheet
     
     
    Sub ListPermutations()
        Dim Rng As Range
        Dim PopSize As Integer
        Dim SetSize As Integer
        Dim Which As String
        Dim N As Double
        Const BufferSize As Long = 4096
         
         
        Set Rng = Range(Range("A1"), Cells(Rows.Count, "A").End(xlUp))
         
        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.CountLarge Then GoTo DataError
         
        Application.ScreenUpdating = False
         
        Set Results = Worksheets.Add
         
        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
        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
                 
                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)
            sValue = sValue & ", " & vAllItems(ItemsChosen(i), 1)
        Next i
         
         'and save it in the buffer
        BufferPtr = BufferPtr + 1
        Buffer(BufferPtr) = Mid$(sValue, 3)
    End Sub 'SavePermutation
    
    



  • di Mister_x (utente non iscritto) data: 25/11/2016 16:06:01

    ciao

    senza un file , penso di aver capito cosa vuoi fare
    selezionare tot nominativi con il tasto CTRL e il mause e da questi creare un elenco e a sua volta una combinazione di due nomi???

    ti allego il file dove da un elenco ho selezionato quattro nomi e creato l'elenco in colonna M ho abbinato in colonna F i vari nomi

    ciao
     
    Option Explicit
    
    Sub ABBINAMENTI()
    Dim Nomi As Range
    Dim i As Long, o As Long, Nriga As Long
    Dim noMe As Variant
    Nriga = 1
    Range("M1:M100,F1:F1000").ClearContents
    Set Nomi = Selection
     For Each noMe In Nomi
       Cells(Nriga, "M") = noMe
       Nriga = Nriga + 1
     Next
     Nriga = 1
    For i = 1 To Cells(Rows.Count, "M").End(xlUp).Row
     noMe = Cells(i, "M")
    For o = i + 1 To Cells(Rows.Count, "M").End(xlUp).Row
      Cells(Nriga, "F") = noMe & " " & Cells(o, "M")
      Nriga = Nriga + 1
    Next o
    Next i
    Set Nomi = Nothing
    End Sub
    






  • di Segugio data: 25/11/2016 16:17:12

    Non proprio, io dovrei creare TUTTE le combinazioni possibili prendendo, per esempio, 2 da colonna A, due da B e due da C. Diciamo che in una cella per ogni colonna dovrei inserire quanti nomi prendere per quel gruppo. Dopodichè la macro genererà tutte le combinazioni senza ripetizioni possibili..
    Ho allegato un file, dove in A2 metto il numero di nomi da prendere (in questo caso 2) e la macro mi estrae tutte le combinazioni da due per i nomi a partire da A3. Io vorrei lo stesso ma aggiungendo altri due gruppi. Per seguire l'esempio, se anche nei due nuovi gruppi inserisco "2", il risultato saranno tutte e combinazioni possibili da 6 nomi, prendendone due da A, due da B e due da C.
    Grazie della tua risposta comunque.



  • di Mister_x (utente non iscritto) data: 25/11/2016 16:32:08

    ciao

    la sub() o macro come la chiami fa questo lavoro
    tu ne scegli quanti ne vuoi , da 3 a tutti e questa fa il raggruppamento di combinazioni a 2 a 2 non creando doppioni

    io ho scelto 4 nominativi
    tizio, gino ,sempronio1 e pino2 e ol risultato in colonna F e questo

    Tizio Sempronio1
    Tizio Gino
    Tizio Pino2
    Sempronio1 Gino
    Sempronio1 Pino2
    Gino Pino2

    ciao





  • di Segugio data: 25/11/2016 16:40:39

    Ti ringrazio ho scaricato il tuo file, ma forse non mi sono spiegato bene.
    Se per esempio scelgo due da ogni gruppo, la mia combinazione deve esser da sei nomi, due da ognuno. Se per esempio ne scelgo tre, la combinazione dovrà essere composta da 9 nomi e così via....



  • di Mister_x (utente non iscritto) data: 25/11/2016 17:05:36

    riciao

    la sub() fa questo lavoro
    ti ho dato la possibilita' di scegliere quello che vuoi , ne puoi attivare 2 da colonna a 3 da B e 1 da C

    per attivarli basta che tu premi il tasto CTRL o control e ti sposti col mause sui niminativi che vuoi e attivi la cella con un clik
    dopo esegui la sub()

    ti riposto il mio file con inserito un bottone di start per far partire la macro
    prova prima col mio file a fare questo lavoro





  • di Segugio data: 25/11/2016 21:11:27

    Ti ringrazio ma non è quello che intendevo. Faccio un altro esempio:

    DIFENSORI CENTROCAMPISTI ATTACCANTI
    Gino Tizio Fabio
    Pino Caio Marco
    Lino Sempronio Luigi

    a me servono tutte le combinazioni con due difensori, due centrocampisti e due attaccanti.
    Quindi:
    Gino, Pino, Tizio, Caio, Fabio, Marco
    Gino, Pino, Tizio, Caio, Fabio, Luigi
    Gino, Pino, Tizio, Caio, Marco, Luigi
    Gino, Pino, Tizio, Sempronio, Fabio, Marco
    Etc Etc....
    Questo inserendo il "2" su ogni colonna. ma nel caso inserissi 3 in colonna A, 2 in colonna B e 3 in Colonna C dovrei ottenere:
    Gino, Pino, Lino, Tizio, Caio, Fabio, Marco, Luigi
    Etc ETc

    Spero di essermi spiegato... ti ringrazio tanto intanto per la pazienza!



  • di Mister_x (utente non iscritto) data: 26/11/2016 00:04:32

    ciao

    a parte la questione che io di calcio me ne intendo una mazza

    seguendo il tuo discorso tu faresti riferimento a dei valori che vai ad inserire in riga2 A,B,C
    dove da riga tre tu hai dei nominativi , ma di questi nominativi quanti ne hai per colonna???
    poniamo l'esempio tu abbia 10 nominativi per colonna e dalla colonna A prendendo 2 nominativi e facendo un abbinamento a 2 avrai un bel numero di abbinamenti 45 solo di questa colonna

    ora penso che tu oltre a postare un file con esempio concreto, con tre colonne di nomi, e quanti sono per colonna sia doveroso per capire cosa vuoi fare
    poniamo l'sempio da te proposto 3,2,3 metti questi in ordine manualmente su una colonna
    altra colonna 2,3,2 e altro esempio

    forse si riuscira' a capire dove vuoi arrivare

    ciao






  • di Segugio data: 26/11/2016 18:11:25

    Ok, allego un file che dovrebbe essere chiaro.
    La sub() dovrebbe restituirmi tutte le combinazioni in base al modulo che inserisco (dal foglio si capisce, sarebbero quanti nomi devo prendere da ogni gruppo) che non superino il budget impostato in cella M4.
    Grazie per la pazienza!