检查一个单词是否可以由一组字母组成(考虑到可以使用这些字母的次数)?

时间:2015-05-17 02:23:21

标签: python list python-3.x subset multiset

我正在进行文字扭曲程序,并且我在检查是否可以从给定的字母组中创建单词时遇到问题。如果没有重复的字母,这很容易,但如果用户输入一个重复字母的单词,我该怎么做呢?我使用了元组,但如果字母重复则不起作用。

为了更清楚,我提供了这个例子:

假设您的信件组为(d,n,a,e,l,i),并且用户输入了字词need。我们可以看到这里使用了e字母两次,但由于我所做的代码(使用元组)只检查列表是否是列表的子集,因此它将need计为正确答案什么时候不是。我如何解决它?

3 个答案:

答案 0 :(得分:1)

一种方法,使用collections.Counter:

from collections import Counter
bag = Counter('dnaeli')
>>> Counter({'a': 1, 'e': 1, 'd': 1, 'i': 1, 'l': 1, 'n': 1})

bag.subtract(Counter('need'))
>>> Counter({'a': 1, 'i': 1, 'l': 1, 'd': 0, 'n': 0, 'e': -1})

if all(v >= 0 for v in bag.values()):
    print 'Word is contained'

注意:Counter.subtract()-操作不同,即Counter.__sub__()Counter.subtract()也会传播负(和零)计数,这是您需要检查[*]。

([*] @StefanPochmann的方法从候选词中减去字母;我的情况则相反。在SP的情况下,正剩余计数是坏的;在我的负面是坏的。所以他的方法不需要关心否定或零计数,但我的确如此。他的复杂性较低,因此更好。)

答案 1 :(得分:0)

是的,设置不起作用,但是多重集合可以。 Counter可用于此目的。

letters = 'dnaeli'
words = 'line', 'linda', 'need', 'den', 'x'

from collections import Counter
for word in words:
    if not Counter(word) - Counter(letters):
        print(word)

打印:

line
linda
den

可替换地:

for word in words:
    if all(letters.count(c) >= word.count(c) for c in word):
        print(word)

如果你的信件都非常大并且你的话很长,那么这会很慢,但是#34;正常使用"没关系。

答案 2 :(得分:0)

您可以尝试从允许列表中删除每个字母,直到您完成或出现问题(意味着您无法构造该字词):

def TestInput(user_input_string, avia_letters_list):
    for each_letter in user_input_string:
        try:
            avia_letters_list.remove(each_letter)
        except ValueError:
            return 'sorry "%s" can not be constructed' % user_input_string  
    return 'good job, "%s" can be constructed' % user_input_string

usable_letters = ['d', 'n', 'a', 'e', 'l', 'i']

print TestInput('need', usable_letters[:])
print TestInput('lid', usable_letters[:])
print TestInput('nail', usable_letters[:])

输出:

sorry "need" can not be constructed
good job, "lid" can be constructed
good job, "nail" can be constructed