我有一个包含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 :(得分: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)
......等等,
答案 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时才能观察到项目不连续。
答案 2 :(得分: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]
编辑:
Eric提出了一个很好的观点,上面的解决方案并不完全有效。如果你希望这个工作,那么谓词需要一些加强。首先,我推导出这些方程式。他们执行窗口操作。说服自己,他们是真的: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)]
同样,这不是最有效的,因为你将计算每个项目的谓词,即使你已经知道你正在把它拿出来。你为优雅付出的代价:)
答案 3 :(得分:0)
不像hexparrot这样光滑的itemgetter
技术,更接近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