Qualche anno fa mi sono trovato nella necessità di creare un algoritmo per ricavare le possibili combinazioni di n elementi su k posizioni: questo mi serviva per sviluppare un sistema per il totogol su Excel (quindi n numeri di mia scelta su 8 posizioni).

Qui sotto trovate l'algoritmo implementato sia in linguaggio C che in Python.

Avevo affrontato il problema sviluppando la seguente funzione ricorsiva in C:

 

void combina(char* data, int n, int k, char* out_str, int out_pos)
{
  int i;
	
  for (i=0; i<=(n-k); i++)
  {
    out_str[out_pos]=data[i];
    if(k > 1)
    {
      combina(&data[i+1], (n-1-i), (k-1), out_str, (out_pos+1));
    }
    else
    {
      out_str[out_pos+1]=0;
      printf(out_str);
      putchar('\\n');
    }
  }
}

Tale funzione si limita a stampare a video il risultato delle possibili combinazioni di un array di n caratteri di classe k.
Segue un esempio di chiamata:

int main(int argc, char *argv[])
{
  char car[] = {'A', 'B', 'C', 'D', 'E'};
  char comodo[6];
	
  combina(car, 5, 3, comodo, 0);
  printf ("\nPremi un tasto\n");
  getch();
  return 0;
}


Il risultato a video è il seguente:

ABC
ABD
ABE
ACD
ACE
ADE
BCD
BCE
BDE
CDE

Negli ultimi mesi ho iniziato ad utilizzare Python e ho provato quindi a riscrivere la funzione in questo linguaggio.

def combinaric( lst, set, curr, n, k ):
    #print( "combinaric: n=" + str(n) + " k=" + str(k) + " curr=" + curr)
        
    for i in range(0,len(set)):
        loccurr = curr + set[i]
        if k==1:
            lst.append(loccurr)
        else:
            combinaric( lst, set[i+1:], loccurr, n-1, k-1)

def combina( set, k ):
    lst = [];
    n = len(set)
    combinaric( lst, set, "", n, k )
    return lst
    
if __name__ == "__main__":
    lst = combina( "ABCDE", 3 )
    for i in range(0,len(lst)):
        print("->"+lst[i])

Nell'implementazione in linguaggio Python ho voluto introdurre:

1) una funzione intermedia (combina) che si occupa di fare la prima chiamata alla funzione ricorsiva, gestendo al suo interno quindi la creazione di una lista di risultati vuota e l'inizializzazione della stringa curr contenente il risultato corrente, per semplificare la vita al chiamante;

2) separare l'esecuzione dell'algoritmo dalla visualizzazione dei risultati, semplicemente caricando in una lista tutti i risultati trovati.