6

だから私は興味深い問題を抱えています。

ごちゃごちゃした単語を書こうとしているのですが、使った文字と使っていない文字を知る必要があります。これまでのところ、以下のコードがあります。

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. x にはない文字が y にある場合は、これを大声で言う必要があります。
  4. 速度は重要ではありませんが、コードの優雅さは重要です。したがって、コードが読みやすくなればなるほど、より良いものになります-私が知っている主観的なものです。
  5. 文字列に変換するだけなので、出力順序は重要ではありませんsorted()

私は他の回答を見てきましたが、これらは主に、1つに表示されず重複を削除する文字のみを与えることに関連しています。

4

3 に答える 3

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']
于 2013-06-29T02:13:53.697 に答える
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 を生成しますが、これは生成しません)。 1)。この点に関して、あなたの要件は少しあいまいです IMO. ただし、stackoverflow の優れた点は、毒を選択するのに十分な答えがあることです。

お役に立てれば。

于 2013-06-29T02:48:29.440 に答える
1

デビッド・ロビンソンの答えに基づいて構築:

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
于 2013-06-29T02:49:29.787 に答える