1

I have a list of words:

words = ['miel', 'extraterrestre', 'al', 'automovil', 'auto', 'revestir']

I want to sort this list using custom alphabet (it contains 26 letters of the alphabet but ordered in a different way):

g = 'zyxwvutsrqponmlkjihgfedcba'

Expected result:

['revestir', 'miel', 'extraterrestre', 'auto', 'automovil', 'al']
Olvin Roght
  • 5,080
  • 2
  • 11
  • 27
Lost111
  • 63
  • 6
  • use the default key and the reverse parameter - https://www.programiz.com/python-programming/methods/list/sort...i think automovil will come before auto – Ctznkane525 Jan 29 '20 at 23:52
  • 3
    Does this answer your question? [How to sort a list of objects based on an attribute of the objects?](https://stackoverflow.com/questions/403421/how-to-sort-a-list-of-objects-based-on-an-attribute-of-the-objects) – politinsa Jan 29 '20 at 23:56
  • Is `g` always the reversed normal alphabet, or do you need a solution for other orders as well? – Kelly Bundy Jan 30 '20 at 00:06
  • What is the issue, exactly? Have you tried anything, done any research? – AMC Jan 30 '20 at 00:41

4 Answers4

2

If speed is important and your list of words is even moderately long, you are probably better off making a lookup rather than searching for the index of each character for each word.

You can use the string function translate() and maketrans() to create a fast way of converting the input strings to a translation for sorting.

For example:

# make translation table 
trans = str.maketrans(g, "".join(sorted(g))) 

# translate words works like:
"revestir".translate(trans)   # 'ivevhgri'

# sort with it:
sorted(l, key=lambda word: word.translate(trans))

# ['revestir', 'miel', 'extraterrestre', 'auto', 'automovil', 'al']

This also has the benefit of being resilient to errors if there are characters in your strings that are not in your alphabet, which index() will choke on. They just get passed through, like:

"reve*stir".translate(trans)
# 'ivev*hgri'
Mark
  • 74,559
  • 4
  • 81
  • 117
1

You can use sorted() and pass as a key lambda function which converts your string into a list of indexes of each char of this string in your custom alphabet:

words = ['miel', 'extraterrestre', 'al', 'automovil', 'auto', 'revestir']
g = 'zyxwvutsrqponmlkjihgfedcba'
sorted_words = sorted(words, key=lambda w: [g.index(c) for c in w])

P.S. This is simplest but definitely not fastest solution, so if your input list is quite big you should consider using solutions from other answers.

Olvin Roght
  • 5,080
  • 2
  • 11
  • 27
1

The more efficient solution, instead of indexing for every letter would be to build a dictionary beforehand and use the get function which is O(1) for every letter in the word.

pos_map = {}
for idx, letter in enumerate(g):
    pos_map[letter] = idx

def key(item):
    return [pos_map.get(c) for c in item]

sorted(words, key=key)
['revestir', 'miel', 'extraterrestre', 'auto', 'automovil', 'al']
gold_cy
  • 9,484
  • 2
  • 16
  • 36
  • Is it more efficient than the other solution that also does this and more efficient than the `translate` solution? – Kelly Bundy Jan 30 '20 at 00:27
  • more efficient than indexing, which I explicitly state – gold_cy Jan 30 '20 at 00:28
  • If speed is critical, I think translate will be faster than the dictionary lookups by a fair margin. But translate and maketrans are a little difficult to understand, so maybe not worth it. – Mark Jan 30 '20 at 00:32
0
g = 'zyxwvutsrqponmlkjihgfedcba'
order={g[i]:i for i in range(len(g))}
sorted(words, key= lambda word:tuple([order[w] for w in word ]))