以下のプログラムで使用されている方法は、素ではないセットを除外するという点で以前のいくつかの回答に似ているため、通常、すべての組み合わせをテストするわけではありません。可能な限りすべてのセットを貪欲に除外することで、以前の回答とは異なります。これにより、NPE のソリューションよりも数倍高速に実行できます。以下は、0 から 20 の範囲の要素を持つ 200、400、... 1000 個のサイズ 6 セットの入力データを使用して、2 つの方法の時間を比較したものです。
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
編集: functionaccrue
では、引数(u, bset, csets)
は次のように使用さ
れ
ます
。
の最初の行がによって置き換えられ
、7 番目の行が によって置き換えられた
場合 (つまり、パラメーターが並べ替えられ、u と bset にデフォルトが指定された場合)、を介して呼び出して、互換性のある共用体のリストを生成できることに注意してください。
accrue
def accrue(csets, u=[], bset=set()):
for v in accrue (ts, y, boc):
accrue
[accrue(listofsets)]
ValueError: zero length field name in format
Python 2.6 を使用した場合に発生するというコメントに記載されているエラーについては、次のことを試してください。
# 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 ではどちらの方法でも機能します。