簡體   English   中英

過濾掉發電機

[英]Filtering out a 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']
['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)

過濾簡單易懂的條件(例如“無前導零”),可以在組合構建級別更有效地進行過濾。

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

遞歸步驟從不考慮以零開頭的子字符串。

一種常見的解決方案是嘗試在使用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')

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM