2016-01-11 9 views
6

Voglio trovare efficientemente permutazioni di un vettore che ha valori legati.permutazioni itertools python con valori legati

esempio se mi vorrebbe per ottenere come output tutte le combinazioni di [0,0,1,2], [0,0,2,1], [0,1,2,0] e così via, ma non voglio per ottenere [0,0,1,2] due volte che è ciò che la norma itertools.permutations(perm_vector) darebbe.

Ho provato quanto segue ma funziona molto lento quando perm_vector grows in len:

vectors_list = [] 
for it in itertools.permutations(perm_vector): 
    vectors_list.append(list(it)) 
df_vectors_list = pd.DataFrame(vectors_list) 
df_gb = df_vectors_list.groupby(list(df_vectors_list.columns)) 
vectors_list = pd.DataFrame(df_gb.groups.keys()).T 

La questione è più generale di "speed-up" la natura, in realtà. Il tempo principale è dedicato alla creazione delle permutazioni di lunghi vettori - anche senza la duplicità, la creazione di permutazioni di un vettore di 12 valori unici prende un "infinito". C'è la possibilità di chiamare itertools iterativamente senza accedere ai dati di tutte le permutazioni ma lavorando su molti di essi?

+4

Eventuali duplicati di [Perché itertools.permutations di Python contengono i duplicati? (Quando l'elenco originale ha duplicati)] (http://stackoverflow.com/questions/6534430/why-does-pythons-itertools-permutations-contain-duplicates-when-the-original) –

+0

Ecco un collegamento [link] esterno (http://blog.bjrn.se/2008/04/lexicographic-permutations-using.html) da un commento nel thread a cui fa riferimento il commento sopra che potrebbe essere utile. – Praveen

+3

c'è una ricetta per questo nel modulo itertools, controlla la ricetta unique_everseen: https://docs.python.org/3/library/itertools.html#itertools-recipes – Copperfield

risposta

0

ne dite di questo:

from collections import Counter 

def starter(l): 
    cnt = Counter(l) 
    res = [None] * len(l) 
    return worker(cnt, res, len(l) - 1) 

def worker(cnt, res, n): 
    if n < 0: 
     yield tuple(res) 
    else: 
     for k in cnt.keys(): 
      if cnt[k] != 0: 
       cnt[k] = cnt[k] - 1 
       res[n] = k 
       for r in worker(cnt, res, n - 1): 
        yield r 
       cnt[k] = cnt[k] + 1 
1

Prova questa se perm_vector è piccolo:

import itertools as iter 
{x for x in iter.permutations(perm_vector)} 

Questo dovrebbe dare valori univoci, perché ora si trasforma in un set, che di default eliminare duplicazioni.

Se perm_vector è di grandi dimensioni, si potrebbe desiderare di provare backtracking:

def permu(L, left, right, cache): 
    for i in range(left, right): 
     L[left], L[i] = L[i], L[left] 
     L_tuple = tuple(L) 
     if L_tuple not in cache:     
      permu(L, left + 1, right, cache) 
      L[left], L[i] = L[i], L[left] 
      cache[L_tuple] = 0 
cache = {} 
permu(perm_vector, 0, len(perm_vector), cache) 
cache.keys() 
+0

Mentre questo funziona tecnicamente, genera ancora tutte le permutazioni duplicate prima del filtraggio, quindi è estremamente inefficiente quando ci sono molti duplicati. – user2357112

+0

@ user2357112 È vero .. Se l'elenco è grande, potrebbe essere necessario utilizzare il backtracking e la memoizzazione per renderlo più efficiente. Ho postato il mio codice sopra (sarebbe bello se ci fosse un modo per evitare "se" all'interno del "ciclo for"). – Rose