Python Forum

Full Version: Sorting List
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi All,

['Finley : 10', 'Evie : 0', 'P1 : 0', 'P2 : 5', 'P1 : 0', 'P2 : 5', 'Finley : 15', 'Evie : 5']
I have this list here. What would I need to do to sort it largest to smallest, based on the numbers, or is this not possible?
Ignore me, I misread. You can pass a key function to sort or sorted. It will need to split the string to extract the number and use that for sorting.

Do you really need to have the data as a single string? An object would make more sense.
x = ['Finley : 10', 'Evie : 0', 'P1 : 0', 'P2 : 5', 'P1 : 0', 'P2 : 5', 'Finley : 15', 'Evie : 5']
x.sort(key=lambda x: int(x.split(":")[1]))
print(x)
Output:
['Evie : 0', 'P1 : 0', 'P1 : 0', 'P2 : 5', 'P2 : 5', 'Evie : 5', 'Finley : 10', 'Finley : 15']
Could also use the name for when the score is the same.
x = ['Finley : 10', 'Evie : 0', 'P1 : 0', 'P2 : 5', 'P1 : 0', 'P2 : 5', 'Finley : 15', 'Evie : 5']
x.sort(key=lambda x: (int(x.split(":")[1]), x))  # Sort key is a tuple(number, name)
print(x)
Output:
['Evie : 0', 'P1 : 0', 'P1 : 0', 'Evie : 5', 'P2 : 5', 'P2 : 5', 'Finley : 10', 'Finley : 15']
(Jan-25-2022, 06:23 PM)deanhystad Wrote: [ -> ]
x = ['Finley : 10', 'Evie : 0', 'P1 : 0', 'P2 : 5', 'P1 : 0', 'P2 : 5', 'Finley : 15', 'Evie : 5']
x.sort(key=lambda x: int(x.split(":")[1]))
print(x)
Output:
['Evie : 0', 'P1 : 0', 'P1 : 0', 'P2 : 5', 'P2 : 5', 'Evie : 5', 'Finley : 10', 'Finley : 15']
Could also use the name for when the score is the same.
x = ['Finley : 10', 'Evie : 0', 'P1 : 0', 'P2 : 5', 'P1 : 0', 'P2 : 5', 'Finley : 15', 'Evie : 5']
x.sort(key=lambda x: (int(x.split(":")[1]), x))
print(x)
Output:
['Evie : 0', 'P1 : 0', 'P1 : 0', 'Evie : 5', 'P2 : 5', 'P2 : 5', 'Finley : 10', 'Finley : 15']



Hello dean,

I tried a different approach but cant get to your result. How come?

dt = {'Finley' : 10, 'Evie' : 0, 'P1' : 0, 'P2' : 5, 'P1' : 0, 'P2' : 5, 'Finley' : 15, 'Evie' : 5}

sorted_dt_value = sorted(dt.values())
print(sorted_dt_value)
Output:
[0, 5, 5, 15]
To be more precise it seem to be a list but x is a dictionnary. Used split to get rid of the comma.
How long did you think about this before giving up? You got a list of sorted numbers because you are sorting the values(), not the items(). You would have noticed this if you tried printing dt.values(). Spend more time trying to answer these kind of questions yourself. Your programming skills will increase much faster if you fix your own problems. Debugging is a great teacher. It produces a deeper and wider understanding than somebody giving you the answer.
dt = {'Finley' : 10, 'Evie' : 0, 'P1' : 0, 'P2' : 5, 'P1' : 0, 'P2' : 5, 'Finley' : 15, 'Evie' : 5}

print(dt.values())
Output:
dict_values([15, 5, 0, 5])
Notice that the names (keys) are gone. The are not going to reappear when sorted.

You cannot sort a dictionary, but you can put the items in a list and sort them.
dt = {'Finley' : 10, 'Evie' : 0, 'P1' : 0, 'P2' : 5, 'P1' : 0, 'P2' : 5, 'Finley' : 15, 'Evie' : 5}

sorted_dt = sorted(dt.items(), key=lambda x: (int(x[1]), x[0]))
print(sorted_dt)
Output:
[('P1', 0), ('Evie', 5), ('P2', 5), ('Finley', 15)]
And of course now that dt is a dictionary you cannot have duplicate names (keys). Duplicate keys are replaced, so the dt dictionary is:
dt = {'Finley': 15, 'Evie': 5, 'P1': 0, 'P2': 5}
Once you have a sorted list of items you can use them to construct a dictionary that is sorted.
dt = {'Finley' : 10, 'Evie' : 0, 'P1' : 0, 'P2' : 5, 'P1' : 0, 'P2' : 5, 'Finley' : 15, 'Evie' : 5}
sorted_dt_items = sorted(dt.items(), key=lambda x: (int(x[1]), x[0]))
sorted_dt = {key:value for key, value in sorted_dt_items}
print(sorted_dt)
Output:
{'P1': 0, 'Evie': 5, 'P2': 5, 'Finley': 15}
(Jan-25-2022, 07:06 PM)deanhystad Wrote: [ -> ]Because you are sorting the values, not the items.
dt = {'Finley' : 10, 'Evie' : 0, 'P1' : 0, 'P2' : 5, 'P1' : 0, 'P2' : 5, 'Finley' : 15, 'Evie' : 5}

sorted_dt = sorted(dt.items(), key=lambda x: (int(x[1]), x[0]))
print(sorted_dt)
Output:
[('P1', 0), ('Evie', 5), ('P2', 5), ('Finley', 15)]
And of course now that this is a dictionary you cannot have duplicate names (keys).

But the original list was between [] not {}, of course i changed that because it would not take it.
It does not return duplicate but finley 10 is not, and obviously when filter it return the latters.

ok

TY
Well yeah, lists and dictionaries have different semantics (and performance characteristics).
I thought this was interesting. You end up with a list of named tuples.

from collections import namedtuple
mylist = ['Finley : 10', 'Evie : 0', 'P1 : 0', 'P2 : 5', 'P1 : 0', 'P2 : 5', 'Finley : 15', 'Evie : 5']
Player = namedtuple('Player', 'name score')
tups = []
for m in mylist:
    alist = m.split()
    name = alist[0]                         
    score = int(alist[2])
    tups.append(Player(name, score))
# sort by name or score
tups.sort(key=lambda x: getattr(x, 'score'), reverse=True)
Example with TypeHints, NamedTuple and closures (nested functions):

from typing import Generator, Iterable, NamedTuple


class ScoreResult(NamedTuple):
    player: str
    score: int


def sort_score(sequence: list[str]) -> list[ScoreResult]:
    def get_elements() -> Generator[ScoreResult, None, None]:
        for element in sequence:
            key, value = element.rsplit(":", maxsplit=1)
            yield ScoreResult(key.strip(), int(value))

    def sorter(item: ScoreResult) -> int:
        return item.score

    return sorted(get_elements(), key=sorter)


mylist = [
    "Finley : 10",
    "Evie : 0",
    "P1 : 0",
    "P2 : 5",
    "P1 : 0",
    "P2 : 5",
    "Finley : 15",
    "Evie : 5",
]


sorted_score = sort_score(mylist)
print(sorted_score)
Of course Dead_EyE obviously knows a lot more about this than EyE, sorry I.
Sitting on the train from Shanghai, I came up with this!
I just wanted to cater for input strings which are maybe not uniform. Then I think you need re.
Still, names with non-word characters will cause trouble.

import re

mylist1 = ['Finley : 10', 'Evie : 0', 'P1 : 0', 'P2 : 5', 'P1 : 0', 'P2 : 5', 'Finley : 15', 'Evie : 5']
mylist2 = ['Finley,10', 'Evie,0', 'P1,0', 'P2,5', 'P1,0', 'P2,5', 'Finley,15', 'Evie,5']
mylist3 = ['Fin#1ley#1,10', 'Ev@ie,0', 'P&1,0', 'P&2,5', 'P*1,0', 'P$2,5', 'Finle-y,15', 'Evi!e,5']

# as long as the name is at the start of the string and the number at the end
# and name and number are separated by a non-word character, this should find them.

# finds a word at the beginning of the string using ^
# stops at the first non-word character
pattern1 = re.compile(r'^\w+')
# matches numbers at the end of the string using $
pattern2 = re.compile(r'\d+$')

# having found them, can't be too hard to sort them!


for m in mylist1:
    print('string is', m)    
    match1 = re.search(pattern1, m)
    start = match1.span()[0]
    stop = match1.span()[1] + 1
    name = m[start:stop]
    print('Name is', name)
    match2 = re.search(pattern2, m)
    start = match2.span()[0]
    stop = match2.span()[1] + 1
    score = m[start:stop]
    print('Score is', score, '\n\n')

for m in mylist2:
    print('string is', m)    
    match1 = re.search(pattern1, m)
    start = match1.span()[0]
    stop = match1.span()[1] + 1
    name = m[start:stop]
    print('Name is', name)
    match2 = re.search(pattern2, m)
    start = match2.span()[0]
    stop = match2.span()[1] + 1
    score = m[start:stop]
    print('Score is', score, '\n\n') 

for m in mylist3:
    print('string is', m)    
    match1 = re.search(pattern1, m)
    start = match1.span()[0]
    stop = match1.span()[1] + 1
    name = m[start:stop]
    print('Name is', name)
    match2 = re.search(pattern2, m)
    start = match2.span()[0]
    stop = match2.span()[1] + 1
    score = m[start:stop]
    print('Score is', score, '\n\n')