Delete common letters in lines

So I have an interesting problem.

I am trying to write a few words, and I need to know which letters I used and which not. So far I have the code below:

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" 

I'm looking for an easy way to remove the letters that are in both, but leave duplicates if necessary.

  • Strings are converted to lowercase, and letters are not deleted.
  • Duplicates matter, so if x = "aa" and y = "a" , then the result is "a" , not "" . I suppose this eliminates the use of sets.
  • If the letter is in y, not in x, she should say it out loud.
  • Speed ​​is not important, but the elegance of the code. So the better the code, the better it is to read - this is the subjective subjectivity that I know.
  • The order of the output does not matter, since I can just convert it to a string and sorted() .

I looked at other answers, but they are mainly related only to letters that do not appear in one and do not duplicate.

+6
source share
3 answers

You can use collections.Counter objects that can be subtracted from each other:

 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())) 

As a demonstration of what is happening:

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

collections.Counter will not allow any account to go below zero if you use the - operator. However, if you use c.subtract (d), then this will allow you to do this. In addition, when using c.elements (), values ​​with a negative number of samples are ignored.

Here is a collection based implementation. 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 

I ran it on the following test suites:

 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") 

Results:

 cbedloosutv af q q asb 

To detect letters that are in y but not in x, you must compare the result of cy.subtract(cx) with the value of cy . For instance:

 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 

Other solutions to this bit that I have seen also fail if the letter exists in y but is repeated more than in x (for example: "hello there" and "hii" will raise an AssertionError in the Josh Smeaton solution but not this one). Your requirement is a bit ambiguous in this regard IMO. The beauty of stackoverflow is that there are enough answers to choose your poison.

Hope this helps.

+1
source

Based on David Robinson's answer:

 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 
+1
source

Source: https://habr.com/ru/post/948361/


All Articles