HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Number Of Matching Elements In Two Lists

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
numberelementstwolistsmatching

Problem

I have many sets of 2 strings. I'm trying to determine the number of matching elements in these 2 strings. The rules are if the strings share a common letter, that's a point, order does matter, but each letter in the first string can only match one of the letters in the second string. So in the strings 'aaaab', 'acccc', only 1 point is awarded because there is only one 'a' to match in the second string. Here are a few examples:

aaabb  bbaaa  5
aabbb  bbbaa  5
aaabb  aabbb  4
aaabb  ccaaa  3
aaaaa  bbbbb  0
ababa  babab  4
aabcc  babaf  3
abcde  abfgh  2
bacde  abdgh  3


Hopefully that gets across how it works.

Here is the most efficient code I've been able to come up with, but its horribly convoluted. I hoping someone could think of something better.

def Score(guess, solution):
    guess = list(guess)
    solution = list(solution)
    c = 0
    for g in guess:
        if g in solution and g != "_":
            c += 1
            solution[solution.index(g)] = "_"
    return c


Surely this isn't the best way to do this, but I haven't been able to figure anything else out. I tried creating an algorithm with Counter and doing guess&solution, which worked, but ended up being way slower. Anyone have any ideas?

Solution

As you have updated your examples, you can write some code to ensure the code we are about to write works properly :

def main():
    """Main function"""
    assert Score('aaabb', 'bbaaa') == 5
    assert Score('aabbb', 'bbbaa') == 5
    assert Score('aaabb', 'aabbb') == 4
    assert Score('aaabb', 'ccaaa') == 3
    assert Score('aaaaa', 'bbbbb') == 0
    assert Score('ababa', 'babab') == 4
    assert Score('aabcc', 'babaf') == 3
    assert Score('abcde', 'abfgh') == 2
    assert Score('bacde', 'abdgh') == 3


Now, the main issue in your code is that we are performing complicated (dirty?) string logic and checking many times if some letter is in a list. The real solution is to count letters in both string. Each letter will count for n points where n is the minimum between the number of times it appears in string 1 and the number of times it appears in string 2.

Using Counter, you can write this :

from collections import Counter

def Score(guess, solution):
    g = Counter(guess)
    s = Counter(solution)
    n = 0
    for l,c in g.iteritems():
        n+=min(c, s[l])
    return n


Abusing generator expressions, you can also write this :

def Score(s1, s2):
    c = Counter(s2)
    return sum(min(n, c[l]) for l,n in Counter(s1).iteritems())

Code Snippets

def main():
    """Main function"""
    assert Score('aaabb', 'bbaaa') == 5
    assert Score('aabbb', 'bbbaa') == 5
    assert Score('aaabb', 'aabbb') == 4
    assert Score('aaabb', 'ccaaa') == 3
    assert Score('aaaaa', 'bbbbb') == 0
    assert Score('ababa', 'babab') == 4
    assert Score('aabcc', 'babaf') == 3
    assert Score('abcde', 'abfgh') == 2
    assert Score('bacde', 'abdgh') == 3
def Score(guess, solution):
    g = Counter(guess)
    s = Counter(solution)
    n = 0
    for l,c in g.iteritems():
        n+=min(c, s[l])
    return n
def Score(s1, s2):
    c = Counter(s2)
    return sum(min(n, c[l]) for l,n in Counter(s1).iteritems())

Context

StackExchange Code Review Q#51525, answer score: 3

Revisions (0)

No revisions yet.