0

Hello I'm trying to sort Player class objects with their name stored as their attribute like this

class Player:
def __init__(self,license_no):
    self.license = license_no
    self.name = input('Oyuncunun adını ve soyadını giriniz: ').replace('ı','I').replace('i','İ').upper()
    self.fide_rating = get_ratings('Oyuncunun FIDE kuvvet puanını giriniz: ')
    self.national_rating = get_ratings('Oyuncunun ulusal kuvvet puanını giriniz: ')
    self.points = 0

I have these objects in a list and I want to sort this list by their name attribute. I can do it with an operator. all together with English alphabetic order just fine but I need to sort them by Turkish alphabet which has characters like 'Ç', 'Ö' etc. How can I do that any help is appreciated?

Ashok
  • 3,190
  • 15
  • 31
  • 1
    Can you also add the code on how you sort the english alphabet so it can give us an idea on what you are trying to achieve? – Andi Domi Feb 06 '21 at 16:36
  • 1
    Does this answer your question? [Is there a standard way to sort by a non-english alphabet? For example, the romanian alphabet is "a ă â b c..."](https://stackoverflow.com/questions/6056842/is-there-a-standard-way-to-sort-by-a-non-english-alphabet-for-example-the-roma) The top answer uses Turkish as an example – Stuart Feb 06 '21 at 16:40
  • player_list.sort(key=lambda x: x.name) works fine with alphabetical sorting of the objects by their name value. But as I said, names starting with turkish characters are on the last part of list. – Ozan Okumuş Feb 06 '21 at 16:40
  • Also https://stackoverflow.com/questions/1097908/how-do-i-sort-unicode-strings-alphabetically-in-python – Stuart Feb 06 '21 at 16:42
  • Stuart, that solution works fine if I have a list of strings as objects but my list is class objects and basically I want to use the method in that link on player.name attribute and sort the player objects list itself. – Ozan Okumuş Feb 06 '21 at 16:43
  • I think using what Stuart has linked it can be used to create a solution – Maxwell Redacted Feb 06 '21 at 16:48

4 Answers4

0

Are you trying to go for something like this?

class S:
  def __init__(self, name):
    self.name = name


c = [S('ç'), S('a')]

# we create a dictionary with the index of the current object in the c list as key
# and name as value
name_to_sort= {}
for ind, obj in enumerate(c):
  name_to_sort[ind]=getattr(obj, 'name')

# in here we sort this dict in base of the values and create a list of list with [index, value]
sorted_by_name = [[k, v] for k, v in sorted(name_to_sort.items(), key=lambda name_to_sort: name_to_sort[1])]

# then in here we create a sorted list by sorting the indexes in the sorted_by_name
# and getting the original object which belonged to that index
sort = []
for ind, val in enumerate(sorted_by_name):
  sort.append(c[val[0]])

# we print the new list by the name
for i in sort:
  print(i.name)

output:

a
ç
Andi Domi
  • 731
  • 2
  • 19
  • 48
  • I am looking for something like that but rather than printing and sorting the names itself I want to sort the objects themselves. like when you print the "c" list in your code you get objects, I want the final result that objects itself are sorted by their name attribute. – Ozan Okumuş Feb 06 '21 at 17:00
0

I believe I have solved it using this library called PyICU which was used here: How do I sort unicode strings alphabetically in Python?

import icu # pip install PyICU


collator = icu.Collator.createInstance(icu.Locale('gr_GR'))

letters="abcçdefgğhıijklmnoöprsştuüvyz" #Turkish alphabet


import random

not_names = []

## creating fake names and players 
for i in range(15):
  not_names.append(''.join([random.choice(letters) for a in range(5)]))

class Player:
  def __init__(self,license_no, name):
    self.license = license_no
    self.name = name

players = []

for idx, name in enumerate(not_names):
  players.append(Player(idx, name))

for player in players: print(player.license, player.name)

players.sort(key=lambda d: collator.getSortKey(d.name)) ## sorting done here
print('\n')

for player in players: print(player.license, player.name)
Maxwell Redacted
  • 569
  • 4
  • 10
0

I have found my solution as I give an integer value for first char of the name. Then using it in a sorted func as key, it sorts the objects based on their name value by given function. Final answer is like below: EDIT: Edited the code by the following question that it only looks for first letter. Now it is looking for every character.

class Player:
    def __init__(self,name):
        self.name = name

    def __repr__(self):
        return f'Player(name={self.name})'


def name_sorting(player):
    chars = 'ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ'
    return [chars.index(player.name[i]) for i in range(len(player.name))]

player_list = [Player('Zeynep'),Player('Ahmet'),Player('Çınar'),Player('Oğuz')]
print(player_list)
print(sorted(player_list, key=name_sorting))
0

Another approach is using str.translate method, which builds a translation table between two sets of strings, like so:

>>> ascii_letters = 'abccdefgghiijklmnooprsstuuvyz'
>>> turkish_letters = 'abcçdefgğhıijklmnoöprsştuüvyz'
#Build the translation table, notice how I've added extra chars in second 
#string to account for special Turkish letters. Basically they should have 
#the same length
>>> turkishTable = str.maketrans(turkish_letters, ascii_letters)
>>> 
>>> s = 'Çınar'
>>> 
>>> s.lower().translate(turkishTable)
'cinar'
>>> player_list = ['Zeynep','Ahmet', 'Çınar', 'Oğuz']
>>> 

>>> sorted(player_list, key=lambda s: s.lower().translate(turkishTable))
['Ahmet', 'Çınar', 'Oğuz', 'Zeynep']

Then you can add another attribute in Player class and call it for example self.translated_name where you save the translated name and sort using this attribute with operator.attrgetter:

>>> from operator import attrgetter
>>> sorted(list_of_player_object, key=attrgetter('translated_name'))
Iron Fist
  • 10,739
  • 2
  • 18
  • 34