![](/img/trans.png)
[英]Find indices of mutually exclusive elements between two arrays in python
[英]Find in python combinations of mutually exclusive sets from a list's elements
在我目前正在開展的一個項目中,我已經實現了我希望程序執行的大約80%,我對結果非常滿意。
在剩下的20%中,我遇到了一個問題,讓我有點困惑如何解決。 這里是:
我想出了一個列表,其中包含幾個數字(任意長度)例如:
listElement[0] = [1, 2, 3]
listElement[1] = [3, 6, 8]
listElement[2] = [4, 9]
listElement[4] = [6, 11]
listElement[n] = [x, y, z...]
其中n可達到40,000左右。
假設每個列表元素是一組數字(在數學意義上),我想要做的是導出互斥集的所有組合; 也就是說,就像上面列表元素的powerset一樣,但排除了所有非不相交集元素。
因此,為了繼續n = 4的示例,我想提出一個具有以下組合的列表:
newlistElement[0] = [1, 2, 3]
newlistElement[1] = [3, 6, 8]
newlistElement[2] = [4, 9]
newlistElement[4] = [6, 11]
newlistElement[5] = [[1, 2, 3], [4, 9]]
newlistElement[6] = [[1, 2, 3], [6, 11]]
newlistElement[7] = [[1, 2, 3], [4, 9], [6, 11]]
newlistElement[8] = [[3, 6, 8], [4, 9]]
newlistElement[9] = [[4, 9], [6, 11]
例如,無效的情況是組合[[1,2,3],[3,6,8]],因為3在兩個元素中是常見的。 有沒有優雅的方法來做到這一點? 我會非常感謝任何反饋。
我還必須指定我不想做powerset函數,因為初始列表可能有相當多的元素(正如我所說n可以達到40000),並且使用如此多元素的powerset永遠不會完成。
我用的是發電機:
import itertools
def comb(seq):
for n in range(1, len(seq)):
for c in itertools.combinations(seq, n): # all combinations of length n
if len(set.union(*map(set, c))) == sum(len(s) for s in c): # pairwise disjoint?
yield list(c)
for c in comb([[1, 2, 3], [3, 6, 8], [4, 9], [6, 11]]):
print c
這會產生:
[[1, 2, 3]]
[[3, 6, 8]]
[[4, 9]]
[[6, 11]]
[[1, 2, 3], [4, 9]]
[[1, 2, 3], [6, 11]]
[[3, 6, 8], [4, 9]]
[[4, 9], [6, 11]]
[[1, 2, 3], [4, 9], [6, 11]]
如果需要將結果存儲在單個列表中:
print list(comb([[1, 2, 3], [3, 6, 8], [4, 9], [6, 11]]))
以下是遞歸生成器:
def comb(input, lst = [], lset = set()):
if lst:
yield lst
for i, el in enumerate(input):
if lset.isdisjoint(el):
for out in comb(input[i+1:], lst + [el], lset | set(el)):
yield out
for c in comb([[1, 2, 3], [3, 6, 8], [4, 9], [6, 11]]):
print c
在許多集合具有共同元素的情況下,這可能比其他解決方案更有效(當然,在最壞的情況下,它仍然必須遍歷powerset的2**n
元素)。
下面的程序中使用的方法類似於幾個先前的答案,排除不相交的集合,因此通常不測試所有組合。 它與以前的答案不同,貪婪地排除它可以盡可能早的所有集合。 這使它的運行速度比NPE的解決方案快幾倍。 下面是兩種方法的時間比較,使用輸入數據200,400,... 1000大小 - 6組,其中元素的范圍為0到20:
Set size = 6, Number max = 20 NPE method
0.042s Sizes: [200, 1534, 67]
0.281s Sizes: [400, 6257, 618]
0.890s Sizes: [600, 13908, 2043]
2.097s Sizes: [800, 24589, 4620]
4.387s Sizes: [1000, 39035, 9689]
Set size = 6, Number max = 20 jwpat7 method
0.041s Sizes: [200, 1534, 67]
0.077s Sizes: [400, 6257, 618]
0.167s Sizes: [600, 13908, 2043]
0.330s Sizes: [800, 24589, 4620]
0.590s Sizes: [1000, 39035, 9689]
在上面的數據中,左列顯示了以秒為單位的執行時間。 數字列表顯示發生了多少單,雙或三聯合。 程序中的常量指定數據集大小和特征。
#!/usr/bin/python
from random import sample, seed
import time
nsets, ndelta, ncount, setsize = 200, 200, 5, 6
topnum, ranSeed, shoSets, shoUnion = 20, 1234, 0, 0
seed(ranSeed)
print 'Set size = {:3d}, Number max = {:3d}'.format(setsize, topnum)
for casenumber in range(ncount):
t0 = time.time()
sets, sizes, ssum = [], [0]*nsets, [0]*(nsets+1);
for i in range(nsets):
sets.append(set(sample(xrange(topnum), setsize)))
if shoSets:
print 'sets = {}, setSize = {}, top# = {}, seed = {}'.format(
nsets, setsize, topnum, ranSeed)
print 'Sets:'
for s in sets: print s
# Method by jwpat7
def accrue(u, bset, csets):
for i, c in enumerate(csets):
y = u + [c]
yield y
boc = bset|c
ts = [s for s in csets[i+1:] if boc.isdisjoint(s)]
for v in accrue (y, boc, ts):
yield v
# Method by NPE
def comb(input, lst = [], lset = set()):
if lst:
yield lst
for i, el in enumerate(input):
if lset.isdisjoint(el):
for out in comb(input[i+1:], lst + [el], lset | set(el)):
yield out
# Uncomment one of the following 2 lines to select method
#for u in comb (sets):
for u in accrue ([], set(), sets):
sizes[len(u)-1] += 1
if shoUnion: print u
t1 = time.time()
for t in range(nsets-1, -1, -1):
ssum[t] = sizes[t] + ssum[t+1]
print '{:7.3f}s Sizes:'.format(t1-t0), [s for (s,t) in zip(sizes, ssum) if t>0]
nsets += ndelta
編輯:在功能accrue
,自變量(u, bset, csets)
被使用如下:
•u =當前集合聯合中的集合列表
•bset =“big set”= u的平坦值=已使用的元素
•csets =候選集=有資格列入的集合列表
請注意,如果第一行accrue
被替換為
def accrue(csets, u=[], bset=set()):
和第七行
for v in accrue (ts, y, boc):
(即,如果參數被重新排序和u和BSET給出的默認值),則accrue
可通過調用[accrue(listofsets)]
,以產生其兼容工會列表。
關於ValueError: zero length field name in format
使用Python 2.6時在注釋中提到的ValueError: zero length field name in format
錯誤中的ValueError: zero length field name in format
,請嘗試以下操作。
# change:
print "Set size = {:3d}, Number max = {:3d}".format(setsize, topnum)
# to:
print "Set size = {0:3d}, Number max = {1:3d}".format(setsize, topnum)
程序中的其他格式可能需要類似的更改(添加適當的字段編號)。 請注意, 2.6頁面中的新內容稱“支持str.format()方法已被反向移植到Python 2.6”。 雖然它沒有說明是否需要字段名稱或數字,但它沒有顯示沒有它們的示例。 相比之下,無論哪種方式都適用於2.7.3。
使用itertools.combinations
, set.intersection
和for-else
循環:
from itertools import *
lis=[[1, 2, 3], [3, 6, 8], [4, 9], [6, 11]]
def func(lis):
for i in range(1,len(lis)+1):
for x in combinations(lis,i):
s=set(x[0])
for y in x[1:]:
if len(s & set(y)) != 0:
break
else:
s.update(y)
else:
yield x
for item in func(lis):
print item
輸出:
([1, 2, 3],)
([3, 6, 8],)
([4, 9],)
([6, 11],)
([1, 2, 3], [4, 9])
([1, 2, 3], [6, 11])
([3, 6, 8], [4, 9])
([4, 9], [6, 11])
([1, 2, 3], [4, 9], [6, 11])
與NPE的解決方案類似,但它沒有遞歸,它返回一個列表:
def disjoint_combinations(seqs):
disjoint = []
for seq in seqs:
disjoint.extend([(each + [seq], items.union(seq))
for each, items in disjoint
if items.isdisjoint(seq)])
disjoint.append(([seq], set(seq)))
return [each for each, _ in disjoint]
for each in disjoint_combinations([[1, 2, 3], [3, 6, 8], [4, 9], [6, 11]]):
print each
結果:
[[1, 2, 3]]
[[3, 6, 8]]
[[1, 2, 3], [4, 9]]
[[3, 6, 8], [4, 9]]
[[4, 9]]
[[1, 2, 3], [6, 11]]
[[1, 2, 3], [4, 9], [6, 11]]
[[4, 9], [6, 11]]
[[6, 11]]
單線程沒有使用itertools包。 這是你的數據:
lE={}
lE[0]=[1, 2, 3]
lE[1] = [3, 6, 8]
lE[2] = [4, 9]
lE[4] = [6, 11]
這是單線:
results=[(lE[v1],lE[v2]) for v1 in lE for v2 in lE if (set(lE[v1]).isdisjoint(set(lE[v2])) and v1>v2)]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.