Here is one way of solving it for N inputs.
from collections import Counter
import unittest
def lower(s: str) -> str:
"""
Filters the input string down to just lowercase letters.
>>> lower('A aaaa xyz xyz')
'aaaaxyzxyz'
"""
return "".join(filter(str.islower, s))
def which(letter: str, biggest: int, *counts: Counter[str]) -> str:
"""Reports which counter has the most of the given letter, typically '1' or '2'."""
for i, count in enumerate(counts):
if count.get(letter) == biggest:
return str(i + 1)
return "999"
def mix(*strings: str) -> str:
counts = [Counter(lower(string)) for string in strings]
ret = []
for letter in sorted(set("".join(strings))):
biggest = max((count.get(letter, 0) for count in counts))
if biggest > 1:
ret.append(which(letter, biggest, *counts) + ":" + letter * biggest)
return "/".join(ret)
class LetterCountTest(unittest.TestCase):
def test_letter_count(self) -> None:
self.assertEqual("2:eee", mix("ee", "eee"))
self.assertEqual("1:ee", mix("ee", "fe"))
self.assertEqual(
"1:aaaa/3:bbb/3:dd",
mix("A aaaa bb c", "bb", "& daaa bbb c d"),
)
Here is one way of solving it for N inputs.
from collections import Counter
import unittest
def lower(s: str) -> str:
"""
Filters the input string down to just lowercase letters.
>>> lower('A aaaa xyz xyz')
'aaaaxyzxyz'
"""
return "".join(filter(str.islower, s))
def which(letter: str, biggest: int, *counts: Counter[str]) -> str:
"""Reports which counter has the most of the given letter, typically '1' or '2'."""
for i, count in enumerate(counts):
if count.get(letter) == biggest:
return str(i + 1)
return "999"
def mix(*strings: str) -> str:
counts = [Counter(lower(string)) for string in strings]
ret = []
for letter in sorted(set("".join(strings))):
biggest = max((count.get(letter, 0) for count in counts))
if biggest > 1:
ret.append(which(letter, biggest, *counts) + ":" + letter * biggest)
return "/".join(ret)
class LetterCountTest(unittest.TestCase):
def test_letter_count(self) -> None:
self.assertEqual("2:eee", mix("ee", "eee"))
self.assertEqual("1:ee", mix("ee", "fe"))
self.assertEqual(
"1:aaaa/3:bbb/3:dd",
mix("A aaaa bb c", "bb", "& daaa bbb c d"),
)
nested functions
Nested functions aren’t doing you any favors in this case. Place them up at top level, please, where they are accessible to other callers, such as unit tests.
doctest
Show us example input and output in the docstring, please. Use "python -m doctest *.py" to verify.
generalize
DRY is sometimes called "the rule of three". So this code isn’t exactly too repetitive.
Nonetheless, the problem statement trivially generalizes from a pair of input strings to N inputs. Consider solving the general problem, at least as far as pre-processing each input string goes. When faced with N inputs, you will be forced to loop over them. I feel this would result in somewhat cleaner code, even for the 2 input case.
zip
I was a little surprised to not see zip() tuples being fed to max() or some custom helper function.
annotations
Typically you should just be annotating the signatures, please.
It's a bit crazy to annotate all those assignments instead.
If mypy
can't figure out the type of what you assigned,
then you probably want to add a --strict
switch to it,
and more carefully annotate the function(s) being called.
The biggest situation where assignment annotations win
is when you initialize some empty container,
so we can't yet see the type of what it will hold,
e.g. words: list[str] = []
.
nested functions
Nested functions aren’t doing you any favors in this case. Place them up at top level, please, where they are accessible to other callers, such as unit tests.
doctest
Show us example input and output in the docstring, please. Use "python -m doctest *.py" to verify.
generalize
DRY is sometimes called "the rule of three". So this code isn’t exactly too repetitive.
Nonetheless, the problem statement trivially generalizes from a pair of input strings to N inputs. Consider solving the general problem, at least as far as pre-processing each input string goes. When faced with N inputs, you will be forced to loop over them. I feel this would result in somewhat cleaner code, even for the 2 input case.
zip
I was a little surprised to not see zip() tuples being fed to max() or some custom helper function.
nested functions
Nested functions aren’t doing you any favors in this case. Place them up at top level, please, where they are accessible to other callers, such as unit tests.
doctest
Show us example input and output in the docstring, please. Use "python -m doctest *.py" to verify.
generalize
DRY is sometimes called "the rule of three". So this code isn’t exactly too repetitive.
Nonetheless, the problem statement trivially generalizes from a pair of input strings to N inputs. Consider solving the general problem, at least as far as pre-processing each input string goes. When faced with N inputs, you will be forced to loop over them. I feel this would result in somewhat cleaner code, even for the 2 input case.
zip
I was a little surprised to not see zip() tuples being fed to max() or some custom helper function.
annotations
Typically you should just be annotating the signatures, please.
It's a bit crazy to annotate all those assignments instead.
If mypy
can't figure out the type of what you assigned,
then you probably want to add a --strict
switch to it,
and more carefully annotate the function(s) being called.
The biggest situation where assignment annotations win
is when you initialize some empty container,
so we can't yet see the type of what it will hold,
e.g. words: list[str] = []
.
nested functions
Nested functions aren’t doing you any favors in this case. Place them up at top level, please, where they are accessible to other callers, such as unit tests.
doctest
Show us example input and output in the docstring, please. Use "python -m doctest *.py" to verify.
generalize
DRY is sometimes called "the rule of three". So this code isn’t exactly too repetitive.
Nonetheless, the problem statement trivially generalizes from a pair of input strings to N inputs. Consider solving the general problem, at least as far as pre-processing each input string goes. When faced with N inputs, you will be forced to loop over them. I feel this would result in somewhat cleaner code, even for the 2 input case.
zip
I was a little surprised to not see zip() tuples being fed to max() or some custom helper function.