Home > front end >  How can I sort this according to the length of the output?
How can I sort this according to the length of the output?

Time:11-19

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 is None).
  • 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 the dict 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])

  • Related