2

私は30個の数字のリストを持っています:

[1, 3, 5, 6, 7, 8, 9, 10, 15, 19, 20, 22, 23, 24, 26, 27, 28, 32, 33, 35, 37, 38, 39, 40, 41, 42, 43, 44, 47, 48]

可能なすべての8桁の組み合わせを出力しています。これは、このコードを使用してうまく機能しています:

possible_combinations = itertools.combinations(dedup_list, 8) 

combos = []
for e in possible_combinations:
    combos.append(e)
print combos

私が今やりたいことは、連続した 3 桁の数字を含むすべての組み合わせを排除することです。次に例を示します。

[1, 5, 9,22、23、24、 33, 37]

提案?

4

4 に答える 4

2

これでうまくいくと思います:

from itertools import combinations, groupby
from operator import itemgetter

data = [1, 3, 5, 6, 7, 8, 9, 10, 15, 19, 20, 22, 23, 24, 26, 27, 28, 32, 33, 35, 37, 38, 39, 40, 41, 42, 43, 44, 47, 48]

def find_consecutive(lst, min_string=3):
    for k, g in groupby(enumerate(lst), lambda (i,x):i-x):
        num_string = map(itemgetter(1), g)
        if len(num_string) >= 3:
            yield num_string

for i in combinations(data, 8):
    if not any(find_consecutive(i, min_string=3)):
        print i

戻り値:

(1, 3, 5, 6, 8, 9, 15, 19)
(1, 3, 5, 6, 8, 9, 15, 20)
(1, 3, 5, 6, 8, 9, 15, 22)
(1, 3, 5, 6, 8, 9, 15, 23)
(1, 3, 5, 6, 8, 9, 15, 24)

...などなど

于 2012-12-15T04:25:21.593 に答える
1

差を計算する方法の 1 つを次に示します ( numpy に似ていますdiff)。

def diff(lst):
    return map(lambda x,y: y-x, lst[:-1],lst[1:])

def remove_consecutive(lst):
    previous = None
    for i, current in enumerate(diff(lst)):
        if previous != 1 and current != 1:
            yield lst[i]
        previous = current
    if current != 1:
        yield lst[-1]

list(remove_consecutive([1, 5, 9, 22, 23, 24, 33, 37]))
# [1, 5, 9, 33, 37]

これは、前の差と次の差がどちらも 1 でない場合にのみ、アイテムが連続していないという観察から機能します。

于 2012-12-15T04:36:07.773 に答える
0

これはおそらく効率賞を獲得することはありませんが、リスト内包のスタイルポイントを獲得できます。

これが私が問題に取り組む方法です。サイズ3のスライディングウィンドウのリストを作成します。

>>> nums = [1, 3, 5, 6, 7, 8, 9, 10, 15, 19, 20, 22, 23, 24, 26, 27, 28, 32, 33, 35, 37, 38, 39, 40, 41, 42, 43, 44, 47, 48]
>>> [nums[i:i+3] for i in xrange(len(nums))]
[[1, 3, 5], [3, 5, 6], [5, 6, 7], [6, 7, 8], [7, 8, 9], [8, 9, 10], [9, 10, 15], [10, 15, 19], [15, 19, 20], [19, 20, 22], [20, 22, 23], [22, 23, 24], [23, 24, 26], [24, 26, 27], [26, 27, 28], [27, 28, 32], [28, 32, 33], [32, 33, 35], [33, 35, 37], [35, 37, 38], [37, 38, 39], [38, 39, 40], [39, 40, 41], [40, 41, 42], [41, 42, 43], [42, 43, 44], [43, 44, 47], [44, 47, 48], [47, 48], [48]]

次のステップでは、連続するアイテムを削除します。これは簡単です。この述語は、連続するアイテムを巧みに除外します。

>>> [nums[i] for i in xrange(len(nums)) if nums[i:i+3] != range(nums[i],nums[i]+3)]
[1, 3, 9, 10, 15, 19, 20, 23, 24, 27, 28, 32, 33, 35, 43, 44, 47, 48]

編集:

エリックは良い点を提起しました、上記の解決策は完全には機能しません。これを機能させたい場合は、述語を強化する必要があります。まず、これらの方程式を導き出しました。それらはウィンドウ操作を実行します。それらが真実であることを自分に納得させてください。

a = [1,2,3,4,5]
i = 2
a[i-0:i+3] == range(a[i-0], a[i]+3) # left
a[i-1:i+2] == range(a[i-1], a[i]+2) # center
a[i-2:i+1] == range(a[i-2], a[i]+1) # right

次に、横にそれを詰め込むことができます...

[a for i,a in enumerate(nums) if all(nums[i-j:i+k] != range(nums[i-j], nums[i]+k) for j,k in zip(xrange(0,3,1), xrange(3,0,-1)))]

ただし、撃たれたくない場合は、述語を関数に引き出します。

consec_to_buddies = lambda i, xs: (
    xs[i-0:i+3] == range(xs[i-0], xs[i]+3) or
    xs[i-1:i+2] == range(xs[i-1], xs[i]+2) or
    xs[i-2:i+1] == range(xs[i-2], xs[i]+1)
)

[a for i,a in enumerate(nums) if not consec_to_buddies(i, nums)]

繰り返しになりますが、これは最も効率的ではありません。これは、アイテムを取り出していることがすでにわかっている場合でも、すべてのアイテムの述語を計算するためです。あなたが優雅さのために支払う価格:)

于 2012-12-15T04:30:32.887 に答える
0

itemgetterヘキサモスが彼らのポストでそれをした方法に近い、hexparrotのような巧妙な技術ではありません。

sec = []
for combo in combo_lst:
    seq = combo[:]
    for i in combo:
        if list(combo[combo.index(i):combo.index(i)+3]) == range(i, i+3):
            break
        combo = combo[combo.index(i)+1:]
        if len(combo) == 0:
            sec.append(seq)
            break
于 2012-12-15T04:32:35.023 に答える