Python 过滤发电机
从生成器中筛选出某些子集的最佳方法是什么。例如,我有一个字符串“1023”,希望生成每个数字的所有可能组合。所有组合将是:Python 过滤发电机,python,filter,generator,Python,Filter,Generator,从生成器中筛选出某些子集的最佳方法是什么。例如,我有一个字符串“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'] ['
['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) 如果使用生成器,最好的过滤方法是什么。目前,我生成了所有的组合,然后在它后面循环,并且仅当子集有效时才继续。为了简单起见,我只打印示例代码中的子集。假设所创建的生成器非常长,或者如果它包含许多无效子集,那么在整个生成器中循环几乎是一种浪费。是否有方法在生成器看到无效项(前导为零的项)时停止生成器,然后将其过滤掉“所有组合”
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)
一种常见的解决方案是在使用
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')
过滤简单而明显的条件,如“无前导零”,可以在组合构建级别更有效地完成
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']]
递归步骤从不考虑以零开头的子字符串。您见过
filter
内置函数吗?@aryamcarthy:在Python 2中,filter
是急切的,它返回一个列表,而不是生成器。在Python 2中,有itertools.ifilter
用于延迟求值。我没有看到Python2标签。我们正在寻找Python3解决方案,但Python2也可以。我如何将“过滤器”集成到我对“所有组合”的列表理解中?你的解决方案没有给出我想要的答案,但我认为你只是想在“产量”之前给我一个过滤器。我在想,但我想我做不到,因为我对“所有组合”有一个列表理解。我想坚持使用列表理解来提高速度,但也许我认为列表理解很快,因为它们在C/C++中为列表预先分配了空间。我不认为生成器理解比生成器函数要快,因为没有要填充的列表-项目一次计算一个。是的,在构建过程中进行过滤更有效。感谢提供示例代码“0”实际上是有效的。只有前导为0的项(表示len至少为2或更多且前导为“0”的项)无效。lambda x:x==“0”或不是x.startswith('0')
有效。