So I wrote this code with the help of Stack Overflow users, and here it is...
def letter_total(filename: str):
chars = list(filename)
chars_unique = set(chars)
chars_unique.remove(' ')
result = []
for x in chars_unique:
result.append([x, chars.count(x)*('*')])
return result
def letter_count(filename: str):
l_count = letter_total(filename)
for c in sorted(l_count):
print(c[0], c[1])
print(letter_count(filename='How was your day'))
and this is the resulting output...
H *
a **
d *
o **
r *
s *
u *
w **
y **
None
but I want my output to be printed in order from most numbers of *
to the least number of them. (if there are same number of '*' in two different letters, then I want it to return the two letters in alphabetical order)
somy output should look like this
a **
o **
w **
y **
d *
H *
r *
s *
How can I accomplish this without using key = lamda and only using sorted()??
CodePudding user response:
You're asking to drive in a screw without using a screwdriver and only using your bare fingers, but okay.
If you store each tally as a list [negative_count, letter]
instead of [letter, stars]
, the default ordering will first sort by negative_count
(longer first) and use letter
as a tie-breaker, exactly as you intended. Note that capitals sort before lowercase letters.
With minimal changes to your code:
def letter_total(filename: str):
chars = list(filename)
chars_unique = set(chars)
chars_unique.remove(' ')
result = []
for x in chars_unique:
result.append([-chars.count(x), x])
return result
def letter_count(filename: str):
l_count = letter_total(filename)
for c in sorted(l_count):
print(c[1], (-c[0]) * '*')
print(letter_count(filename='How was your day'))
Then a couple more pointers:
letter_count
is already doing the printing; no need to also print its return value (which isNone
).- It's more efficient and idiomatic to use tuples
(stars, letter)
instead of lists here. - This code is O(n²) which means it's rather inefficient. For each unique letter, it's running through the entire string to count just that letter. It's more efficient to run through the string once, and keep a tally in a
dict
. Then as the last step, convert thedict
into a list of tuples.
Putting all that together:
def letter_total(filename: str):
l_count = {}
for x in filename:
if x != ' ':
if x not in l_count:
l_count[x] = 0
l_count[x] -= 1
result = [(count, letter) for letter, count in l_count.items()]
return result
def letter_count(filename: str):
l_count = letter_total(filename)
for c in sorted(l_count):
print(c[1], (-c[0]) * '*')
print(letter_count(filename='How was your day'))
I understand you're just learning, but in production code, I would recommend collections.Counter
which does exactly this job for you:
>>> from collections import Counter
>>> list(Counter('How was your day').items())
[(' ', 3), ('H', 1), ('a', 2), ('d', 1), ('o', 2), ('r', 1), ('s', 1), ('u', 1), ('w', 2), ('y', 2)]
CodePudding user response:
clean the input string
then use Counter with its method most_common to get a list of letters counted by their occurence
then group the output list of tuples l by second element
apply sorted
from collections import Counter
from typing import List, Tuple
s: str = 'How was your day'.replace(" ", "")
ll: List[Tuple[str, int]] = Counter(s).most_common()
res = sum([sorted(v, key=lambda ch: ch[0].lower()) for k,v in groupby(ll), lambda x: x[1])], [])
res = [(x, y * "*") for x,y in res]
OUTPUT:
[('a', '**'),
('o', '**'),
('w', '**'),
('y', '**'),
('d', '*'),
('H', '*'),
('r', '*'),
('s', '*'),
('u', '*')]
CodePudding user response:
This way:
sorted(sorted(l_count), key = lambda i:-i[1])