2016-01-11 25 views
6

bağlı değerlere sahip bir vektörün permütasyonlarını bulmak istiyorum.python itertools permütasyonları bağlı değerlerle

Ör eğer çıktı olarak diğerlerinin hepsi [0,0,1,2], [0,0,2,1], [0,1,2,0] kombinasyonlarını ve elde etmek isteyeyim ama [0,0,1,2] elde etmek istemiyoruz iki kez standart itertools.permutations(perm_vector) verecekti budur.

Aşağıdaki çalıştı ama len içinde perm_vector grows zaman gerçekten YAVAŞ çalışır:

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 

soru aslında daha genel "hız-up" bir yapıya sahiptir. Asıl zaman, uzun vektörlerin permütasyonlarının yaratılması için harcanır - hatta ikilik olmadan bile, 12 eşsiz değerin bir vektörünün permütasyonlarının yaratılması bir "sonsuzluk" alır. Tüm permütasyon verisine erişmeden itertools itetools çağırmak için bir olasılık var mı ama demet üzerinde çalışıyor? Bu konuda

+4

Neden Python'un itertools.permutations çiftleri içermiyor [Olası yinelenen? (Orijinal liste çiftleri olduğunda)] (http://stackoverflow.com/questions/6534430/why-does-pythons-itertools-permutations-contain-duplicates-when-the-original) –

+0

İşte bir harici [link] (http://blog.bjrn.se/2008/04/lexicographic-permutations-using.html), yukarıdaki yorum tarafından atıfta bulunulan ve bu konuda yararlı olabilecek bir yorumdan. – Praveen

+3

itertools modülünde bunun için bir tarif var, unique_everseen tarifini kontrol edin: https://docs.python.org/3/library/itertools.html#itertools-recipes – Copperfield

cevap

0

Nasıl: perm_vector küçükse

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

bu deneyin: şimdi varsayılan olarak tekrarları silmek bir dizi haline gelir çünkü

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

Bu, size benzersiz değerler vermelidir.

perm_vector büyükse

, sen geriye deneyin isteyebilirsiniz:

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

Bu teknik olarak çalışır, ancak hala filtrelemeden önce tüm yinelenen permütasyonları üretir, bu nedenle çok sayıda yinelenen olduğunda aşırı derecede verimsizdir. – user2357112

+0

@ user2357112 Bu doğru .. Eğer liste büyükse, daha verimli hale getirmek için backtracking ve memoization kullanmanız gerekebilir. Yukarıdaki kodumu yayınladım (eğer "for döngüsü" içinde "if" den kaçınmak için bir yol varsa harika olurdu). – Rose

İlgili konular