简体   繁体   English

过滤掉发电机

[英]Filtering out a generator

Whats the best way to filter out some subsets from a generator. 什么是从生成器中滤除某些子集的最佳方法。 For example I have a string "1023" and want to produce all possible combinations of each of the digits. 例如,我有一个字符串“ 1023”,并希望产生每个数字的所有可能组合。 All combinations would be: 所有组合将是:

['1', '0', '2', '3']
['1', '0', '23']
['1', '02', '3']
['1', '023']
['10', '2', '3']
['10', '23']
['102', '3']
['1023']

I am not interested in a subset that contains a leading 0 on any of the items, so the valid ones are: 我对包含任何项目的前导0的子集不感兴趣,因此有效的是:

['1', '0', '2', '3']
['1', '0', '23']
['10', '2', '3']
['10', '23']
['102', '3']
['1023']

I have two questions. 我有两个问题。

1) If using a generator, whats the best way to filter out the ones with leading zeroes. 1)如果使用发生器,什么是过滤掉前导零的最好方法? Currently, I generate all combinations then loop through it afterwards and only continuing if the subset is valid. 当前,我生成所有组合,然后循环遍历,仅在子集有效时才继续。 For simplicity I am only printing the subset in the sample code. 为简单起见,我仅在示例代码中打印子集。 Assuming the generator that was created is very long or if it constains a lot of invalid subsets, its almost a waste to loop through the entire generator. 假设创建的生成器很长,或者包含很多无效子集,则遍历整个生成器几乎是浪费。 Is there a way to stop the generator when it sees an invalid item (one with leading zero) then filter it off 'allCombinations' 有没有一种方法可以在看到无效项(前导零的项)时停止生成器,然后将其过滤掉“ allCombinations”

2) If the above doesn't exist, whats a better way to generate these combinations (disregarding combinations with leading zeroes). 2)如果以上都不存在,那么有什么更好的方法来生成这些组合(不考虑前导零的组合)。

Code using a generator: 使用生成器的代码:

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)

Filtering for an easy and obvious condition like "no leading zeros", it can be more efficiently done at the combination building level. 过滤简单易懂的条件(例如“无前导零”),可以在组合构建级别更有效地进行过滤。

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

Generating every combination of cuts, so long it's not even funny: 生成切割的每种组合,以至于它甚至都不有趣:

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

Only those where no fragment has leading zeros: 仅那些没有片段前导零的片段:

>>> list(generate_pieces('10002', lambda x: not x.startswith('0')))
[['10002'], ['1000', '2']]

Substrings that start with a zero were never considered for the recursive step. 递归步骤从不考虑以零开头的子字符串。

One common solution is to try filtering just before using yield . 一种常见的解决方案是尝试在使用yield之前进行过滤。 I have given you an example of filtering just before 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)))

EDIT: Added in a generator comprehension alternative 编辑:在生成器替代中添加

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM