4

(I use Python 2 here)

I have a list of dictionaries, say

dei = [{'name': u'Thor'}, {'name': u'Œdipus'}, {'name': u'Creon'}]

I would like to sort that list by their 'name' attribute. This is easily done so:

dei.sort(key=lambda d: d['name'])

Now, because Python’s alphabetical sorting is ASCII-driven, the result will be

[{'name': u'Creon'}, {'name': u'Thor'}, {'name': u'Œdipus'}]

while I’d like Œdipus to be between Creon and Thor.

Following this suggestion, I use PyICU’s collator.getSortKey() function (let’s rename it sortKey() for readability), which works this way on a list strings of strings:

strings.sort(key=sortKey)

My problem here: as I cannot modify the sortKey() function anyhow, how can I use it to sort a list of more complex objects (here, dictionaries) according to some attribute?

The only way I found for the moment is by extracting the values of the dictionary in a separate list, sorting it, then implementing a custom compare(a, b) function returning −1, 0 or 1 depending on the index of a and b in the separate list, and calling sort() with this compare() function:

names = sorted([d['name'] for d in dei], key=sortKey)

def compare(a, b):
    if names.index(a) < names.index(b):
        return -1
    elif names.index(a) > names.index(b):
        return 1
    else:
        return 0

results = dei.sort(key=lambda d: d['name'], cmp=compare)

which I don’t find very elegant.

Community
  • 1
  • 1
Eoshyn
  • 43
  • 2
  • 1
    The problem isn't the key. The problem is you disagree with python over the order of the alphabet. If that 'ae' symbol comes after 'c' in your language, can you just use localization? Otherwise you must provide the comparison function telling it what order to sort the alphabet. But providing your comparison function just on a few exact words seems shortsighted. – Kenny Ostrom Aug 05 '16 at 16:41
  • Yes, alphabetical sorting is language-dependent, that's why I want to use PyICU, which precisely implements it for any language. – Eoshyn Aug 05 '16 at 18:47

1 Answers1

2

You can use your own key that internally calls getSortKey with correct value:

>>> import icu
>>> dei = [{'name': u'Thor'}, {'name': u'Œdipus'}, {'name': u'Creon'}]
>>> collator = icu.Collator.createInstance()
>>> dei.sort(key=lambda x: collator.getSortKey(x['name']))
>>> dei
[{'name': 'Creon'}, {'name': 'Œdipus'}, {'name': 'Thor'}]
niemmi
  • 17,113
  • 7
  • 35
  • 42
  • Oh sh*, it… works :-o This was one of the first thing I tried, but I tried it in pdb, which for any reason wouldn't accept `collator` in the lambda (`global name 'collator' is not defined`). It took me a while before figuring out the problem was only in pdb, and I… completely forgot to test the simplest solution again. Thanks! (And shame on me!) – Eoshyn Aug 05 '16 at 18:44