Python - For Itertools Permutations循环,如何不创建无尽的Elif语句?

时间:2013-09-27 06:27:21

标签: python if-statement for-loop permutation

我是一个python /编程新手,已经有几个月了。希望这块代码对于SO来说不是太大或太过分,但是如果没有完整的上下文,我无法想象如何提出问题。所以这里:

import re
import itertools

nouns = ['bacon', 'cheese', 'eggs', 'milk', 'fish', 'houses', 'dog']
CC = ['and', 'or']

def replacer_factory():
    def create_permutations(match):
        group1_string = (match.group(1)[:-1]) # strips trailing whitespace
        # creates list of matched.group() with word 'and' or 'or' removed
        nouns2 = filter(None, re.split(r',\s*', group1_string)) + [match.group(3)] 
        perm_nouns2 = list(itertools.permutations(nouns2))
        CC_match = match.group(2) # this either matches word 'and' or 'or'

        # create list that holds the permutations created in for loop below
        perm_list = []
        for comb in itertools.permutations(nouns2):
            comb_len = len(comb)
            if comb_len == 2:
                perm_list.append(' '.join((comb[0], CC_match, comb[-1])))

            elif comb_len == 3:
                perm_list.append(', '.join((comb[0], comb[1], CC_match, comb[-1])))

            elif comb_len == 4:
                perm_list.append(', '.join((comb[0], comb[1], comb[2], CC_match, comb[-1])))

        # does the match.group contain word 'and' or 'or'
        if (match.group(2)) == "and":
            joined = '*'.join(perm_list)
            strip_comma = joined.replace("and,", "and")
            completed = '|'+strip_comma+'|'
            return completed

        elif (match.group(2)) == "or":
            joined = '*'.join(perm_list)
            strip_comma = joined.replace("or,", "or")
            completed = '|'+strip_comma+'|'
            return completed       

    return create_permutations

def search_and_replace(text):
    # use'nouns' and 'CC' lists to find a noun list phrase
    # e.g 'bacon, eggs, and milk' is 1 example of a match
    noun_patt = r'\b(?:' + '|'.join(nouns) + r')\b'
    CC_patt = r'\b(' + '|'.join(CC) + r')\b' 
    patt = r'((?:{0},? )+){1} ({0})'.format(noun_patt, CC_patt)

    replacer = replacer_factory()
    return re.sub(patt, replacer, text)

def main():
    with open('test_sentence.txt') as input_f:
        read_f = input_f.read()

    with open('output.txt', 'w') as output_f:
        output_f.write(search_and_replace(read_f))


if __name__ == '__main__':
    main()

' test_sentence.txt'的内容:

I am 2 list with 'or': eggs or cheese.
I am 2 list with 'and': milk and eggs.
I am 3 list with 'or': cheese, bacon, and eggs.
I am 3 list with 'and': bacon, milk and cheese.
I am 4 list: milk, bacon, eggs, and cheese.
I am 5 list, I don't match.
I am 3 list with non match noun: cheese, bacon and pie.

所以,代码一切都很好,但是我遇到了一个限制,我无法弄清楚如何解决。此限制包含在for循环中。目前我只创建了“如果'和' elif'只有elif comb == 4:的陈述。我实际上希望它变得无限制,继续elif comb == 5:elif comb == 6:elif comb == 7:。 (嗯,在实际情况中,我真的不需要超越elif comb == 20,但重点是相同的,我想允许这种可能性)。然而,创造这么多的“elif”并不可行。声明。

关于如何解决这个问题的任何想法?

请注意' test_sentence.txt'以及变量'名词'的列表这里只是样品。我的名词'列表在1000年代,我将使用包含在' test_sentence.txt中的文本的更大文档。

干杯 达伦

P.S - 我努力想出一个合适的头衔!

1 个答案:

答案 0 :(得分:3)

如果您注意到,if-elif语句中的每一行都遵循大致相同的结构:首先获取comb列表中除最后一个之外的每个元素,添加{{1} },然后添加最后一项。

如果我们把它写成代码,我们会得到这样的结果:

CC_match

然后,在head = list(comb[0:-1]) head.append(CC_match) head.append(comb[-1]) perm_list.append(', '.join(head)) 循环中,您可以替换for语句:

if-elif

您还应考虑添加一些错误检查,以便在for comb in itertools.permutations(nouns2): head = list(comb[0:-1]) head.append(CC_match) head.append(comb[-1]) perm_list.append(', '.join(head)) 列表的长度等于零或一个时,程序不会产生奇怪的反应。