删除字符串中的常用字母

时间:2013-06-29 02:05:03

标签: python string

所以我有一个有趣的问题。

我正在尝试写一些单词混乱,我需要知道我使用了哪些字母,哪些字母没有。到目前为止,我有以下代码:

def remove_common(x,y):
   sort = sort = lambda x: "".join(c for c in sorted(x.lower()) if c.isalpha())
   x,y  = sort(x), sort(y)
   //some code that removes y from x
   return leftovers

print remove_common("Lets chat about code","that cool cat")
print remove_common("A silly word","a lil sword")
print remove_common("The Thing","Height")

>>> "bdeesu"
>>> "iy"
>>> "tn"

我正在寻找一种简单的方法来删除两者中的字母,但在必要时留下重复的内容。

  1. 字符串转换为小写,非字母被删除
  2. 重复事项,因此如果x = "aa"y = "a",则结果为"a",而不是""。我认为这排除了套装的使用。
  3. 如果y中的字母不在x中,则应该大声说出来。
  4. 速度并不重要,但代码的优雅是。所以代码读得越好越好 - 我知道的那种主观。
  5. 输出顺序并不重要,因为我只能将其转换为字符串sorted()
  6. 我已经查看了其他答案,但这些答案主要与仅提供未出现在一个字母中的字母有关并删除重复字段。

3 个答案:

答案 0 :(得分:7)

您可以使用collections.Counter个对象,这些对象可以相互减去:

import collections

def remove_common(x,y):
    count = lambda x: collections.Counter(c for c in x.lower() if c.isalpha())
    cx, cy = count(x), count(y)
    diff  = cx - cy
    rev_diff = cy - cx
    assert len(rev_diff) == 0, "%s in y and not x" % "".join(rev_diff.elements())

    return "".join(sorted(diff.elements()))

作为正在发生的事情的演示:

>>> c1 = collections.Counter("hello world")
>>> c2 = collections.Counter("hey worlds")
>>> c1 - c2
Counter({'l': 2, 'o': 1})
>> (c1 - c2).elements()
['l', 'l', 'o']

答案 1 :(得分:1)

如果您使用collections.Counter运算符,

-将不会让任何计数低于零。但是,如果您使用c.subtract(d),那么它将允许您这样做。此外,使用c.elements()时,将忽略具有负计数的值。

这是一个基于collections.Counter:

的实现
import collections                                                              

def remove_common(x, y):                                                        
    sort = lambda x: "".join(c for c in sorted(x.lower()) if c.isalpha())       
    x, y = list(sort(x)), list(sort(y))                                         
    cx = collections.Counter(x)                                                 
    cy = collections.Counter(y)
    cx.subtract(cy)

    result = ""
    for letter, count in cx.iteritems():
        for i in range(abs(count)):
            result += letter

    return result      

我在以下测试集上运行它:

print remove_common("Lets chat about code","that cave")                     
print remove_common("basdf aa", "a basd")                                   
print remove_common("asdfq", "asdf")                                        
print remove_common("asdf", "asdfq")                                        

print remove_common("aa bb s", "a bbb")

结果:

cbedloosutv
af
q
q
asb

要检测y中但不是x中的字母,您应该将cy.subtract(cx)的结果与cy的值进行比较。例如:

cz = collections.Counter(cy) # because c.subtract(..) modifies c
cz.subtract(cx)
for letter, count in cz.iteritems():
    if count == cy[letter]: # in the case that there were none of letter in x
        assert False

如果y中存在一个字母但是重复的次数比x中的更多次,我看到的其他解决方案也失败了(例如:'hi there'和'hii'会在Josh Smeaton的解决方案中产生AssertionError但不是这个)。在这方面你的要求有点模糊IMO。 stackoverflow的美妙之处在于,有足够的答案来挑选你的毒药。

希望这有帮助。

答案 2 :(得分:1)

以David Robinsons的回答为基础:

import collections.Counter as C
def remove_common(x,y):
    s1,s2=filter(str.isalpha, x.lower()),filter(str.isalpha, y.lower())
    c1,c2 = C(s1),C(s2)
    if any(c2-c1):
        assert False
    return list((c1-c2).elements())

>>> remove_common('hi there','hi')
['h', 'r', 'e', 'e', 't']
>>> x,y='Lets chat about code','that cool cat'
>>> remove_common(x,y)
['u', 's', 'b', 'e', 'e', 'd']
>>> remove_common('hi','ho')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in remove_common
AssertionError