什么是从生成器中过滤掉一些子集的最佳方法。例如,我有一个字符串" 1023"并希望生成每个数字的所有可能组合。所有组合都是:
['1', '0', '2', '3']
['1', '0', '23']
['1', '02', '3']
['1', '023']
['10', '2', '3']
['10', '23']
['102', '3']
['1023']
我对任何项目中包含前导0的子集不感兴趣,因此有效的是:
['1', '0', '2', '3']
['1', '0', '23']
['10', '2', '3']
['10', '23']
['102', '3']
['1023']
我有两个问题。
1)如果使用发生器,最好的方法是过滤掉带有前导零的发生器。目前,我生成所有组合,然后循环遍历它,并且只有在子集有效时才继续。为简单起见,我只在示例代码中打印子集。假设创建的生成器很长或者它占用了很多无效的子集,那么在整个生成器中循环几乎是浪费。有没有办法在发生器看到无效的项目(一个前导零)时停止它,然后将其过滤掉' allCombinations'
2)如果上述情况不存在,那么生成这些组合的更好方法是什么(忽略带有前导零的组合)。
使用生成器的代码:
import itertools
def isValid(subset): ## DIGITS WITH LEADING 0 IS NOT VALID
valid = True
for num in subset:
if num[0] == '0' and len(num) > 1:
valid = False
break
return valid
def get_combinations(source, comb):
res = ""
for x, action in zip(source, comb + (0,)):
res += x
if action == 0:
yield res
res = ""
digits = "1023"
allCombinations = [list(get_combinations(digits, c)) for c in itertools.product((0, 1), repeat=len(digits) - 1)]
for subset in allCombinations: ## LOOPS THROUGH THE ENTIRE GENERATOR
if isValid(subset):
print(subset)
答案 0 :(得分:2)
过滤一个简单而明显的条件,例如"没有前导零",它可以在组合建筑层面更有效地完成。
def generate_pieces(input_string, predicate):
if input_string:
if predicate(input_string):
yield [input_string]
for item_size in range(1, len(input_string)+1):
item = input_string[:item_size]
if not predicate(item):
continue
rest = input_string[item_size:]
for rest_piece in generate_pieces(rest, predicate):
yield [item] + rest_piece
生成剪辑的每一个组合,只要它不是很有趣:
>>> list(generate_pieces('10002', lambda x: True))
[['10002'], ['1', '0002'], ['1', '0', '002'], ['1', '0', '0', '02'], ['1', '0', '0', '0', '2'], ['1', '0', '00', '2'], ['1', '00', '02'], ['1', '00', '0', '2'], ['1', '000', '2'], ['10', '002'], ['10', '0', '02'], ['10', '0', '0', '2'], ['10', '00', '2'], ['100', '02'], ['100', '0', '2'], ['1000', '2']]
只有那些没有片段有前导零的那些:
>>> list(generate_pieces('10002', lambda x: not x.startswith('0')))
[['10002'], ['1000', '2']]
从零开始的子字符串从未被考虑用于递归步骤。
答案 1 :(得分:0)
一种常见的解决方案是在使用yield
之前尝试过滤。我给了你一个在yield之前过滤的例子:
import itertools
def my_gen(my_string):
# Create combinations
for length in range(len(my_string)):
for my_tuple in itertools.combinations(my_string, length+1):
# This is the string you would like to output
output_string = "".join(my_tuple)
# filter here:
if output_string[0] != '0':
yield output_string
my_string = '1023'
print(list(my_gen(my_string)))
编辑:在生成器理解替代中添加
import itertools
my_string = '1023'
my_gen = ("".join(my_tuple)[0] for length in range(len(my_string))
for my_tuple in itertools.combinations(my_string, length+1)
if "".join(my_tuple)[0] != '0')