解决单词拼图?

时间:2015-06-17 11:35:48

标签: python

我正在尝试创建一个程序,找到包含所需字母x的一定长度或更长的所有单词,并且单词中的其余字母是从y中的字母中提取的(这是在NYT中找到的拼图)。

由于我正在尝试逐步完成此操作,因此我首先创建一个长度为> =所需长度的所有单词的单词列表,然后创建包含所需字母的所有单词的列表。

然后,我浏览该列表中每个单词中的每个字母,看它们是否包含不在输入字母中的字母,或者使用该字母的次数多于输入中的字母。如果发生这种情况,我会从列表中删除该单词。

最后,我打印满足条件的所有单词。但是,它不起作用,我不知道为什么。我确定我在这里犯了一个真正的菜鸟错误,但我会喜欢任何建议。非常感谢,请原谅我可怕的代码,我只学习Python两周了!

data = [line.strip() for line in open("wordsEn.txt", 'r')]
req = str(input("Please enter the required letter "))
set = str(input("Please enter the other letters "))
completeset = req + set
lenreq = int(input("Please enter minimum word length "))
panswers = []
usedict = [word for word in data if len(word) >= lenreq]
for word in usedict:
    if req in word:
        panswers = panswers + [word]
panswerstest = panswers
for word in panswerstest:
    for w in word:
        if word.count(w) > completeset.count(w):
            try:
                panswers.remove(word)
            except:
                continue
print(panswers)

1 个答案:

答案 0 :(得分:1)

由于您显然对Python很陌生,所以这里有一些关于您的代码的提示(这是Code Review比Stack Overflow更多,但是很好):

  • 不要将整个单词列表作为列表加载到第一行;这非常耗费内存,会降低程序速度。一个常见的结构是

    with open('myfile.txt') as f:
        for line in f:
            do_stuff_with(line)
    

    for line in f循环一次只加载一行,因此一次只能存储一行内存。这样效率更高。

    更一般地说,您要创建几个大型列表:datapanswerspanswerstest。当我尝试你的代码时,它因为列表太大而窒息。 (当我开始写这个答案时,我开始运行它;它还没有完成。)

    如果你一次检查一个单词,它是否匹配,打印到stdout,然后直接进入下一行会更好。

  • 不要将set用于变量名称。 setbuilt-in function,并且压倒这些是不好的做法(因为你会以意想不到的方式导致事情中断)。

  • 分隔用于过滤单词列表的代码和用于获取用户输入的代码。我至少有两个功能:get_user_input()check_word_match(word)。这使得您的代码可以重复使用,并且您可以从用于匹配单词的代码中解开用于输入用户输入的代码(例如,将长度转换为整数)。

  • 使用更长的变量名称。字符很便宜,它使您更容易阅读代码。 (例如lenreq〜> required_lengthpanswers ~> possible_answers

  • 不清楚匹配是否区分大小写(如果是,则应该向用户说明)。如果需要,在代码中填充lower()将有助于使其不区分大小写。

  • 在Python 3中,input()会返回一个字符串,因此无需使用str()重新生成字符串。

  • 使用裸except:总是一个坏主意,因为你可以捕捉到你不想要的错误(这会捕获所有错误)。最好抓住你知道会引发的特定异常。

    在这种情况下,我猜你正在抛出一个ValueError,因为你试图删除一个不在列表中的项目,所以你应该使用except ValueError:。 (虽然我不确定如何;一旦panswerstestpanswers的副本,我就不确定如何发生这种情况。)

所以这就是我重写代码的方式:

def get_user_input():
    user_input = {}
    user_input['required'] = input('Please enter the required letter ')
    user_input['additional'] = input('Please enter the other letters ')
    user_input['minimum_length'] = int(input('Please enter the minimum word length '))
    return user_input


def match_word(word, required, additional, minimum_length):
    '''
    Returns True if a word matches the following criteria:
     1) It is at least minimum_length
     1) It contains the required characters
     2) It only contains letters from (required + additional)
    '''
    if len(word) < minimum_length:
        return False

    if required not in word:
        return False

    complete_char_set = required + additional
    for char in word:
        if word.count(char) > complete_char_set.count(char):
            return False

    return True


user_input = get_user_input()

# /usr/share/dict/words is a list of English words found on many Unix
# systems; swap it out for any text file containing a list of words.
with open('/usr/share/dict/words') as f:
    for line in f:
        word = line.strip()
        if match_word(word,
                      required=user_input['required'],
                      additional=user_input['additional'],
                      minimum_length=user_input['minimum_length']):
            print(word)

我已将代码分成两个函数并删除了所有大型列表。该版本运行得更快(几秒钟),因为没有任何大型循环需要担心。