2012-12-15 118 views
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]

建議?

+0

你想如何處理長度大於3的連續序列?對於1,20,21,22,23,24,30,期望的輸出是多少? –

+0

這是非常好的一點,因爲會有4或5個連續數字的實例。我想消除所有3個事件。 – Trapp

+0

只是領先的數字或任何地方? – Anycorn

回答

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) 

...等等,等等

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)] 

再次,這是不是最有效的,因爲你會被計算爲每個項目的斷言,即使你已經知道你正在服用它出。你付出的代價優雅:)

+0

這是一個了不起的列表理解,但只消除了連續三個*的*第一*。 (例如:'22,23,24' - >'23,24') – Eric

0

不是光滑的itemgetter技術像hexparrot,更接近Balthamos如何在他們的職位。

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 
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.