Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A more pythonic way to write this expression?

Tags:

python

sorting

I'm supposed to take a list of words and sort it, except I need to group all Strings that begin with 'x' first.

Here's what I got:

list_1 = []
list_2 = []

for word in words:
  list_1.append(word) if word[0] == 'x' else list_2.append(word)

return sorted(list_1) + sorted(list_2)

But I have a feeling there is a much more elegant way to do this...

EDIT

Example: ['mix', 'xyz', 'apple', 'xanadu', 'aardvark'] yields ['xanadu', 'xyz', 'aardvark', 'apple', 'mix'].

like image 885
helpermethod Avatar asked Nov 02 '10 11:11

helpermethod


2 Answers

>>> words = ['xoo', 'dsd', 'xdd']
>>> sorted(words, key=lambda x: (x[0] != 'x', x))
['xdd', 'xoo', 'dsd']

Explanation: the key function returns a pair (tuple). The first element is False or True, depending on whether the first char in the string is 'x'. False sorts before True, so strings starting with 'x' will be first in the sorted output. The second element in the tuple will be used to compare two elements that are the same in the first element, so all the strings starting with 'x' will be sorted amongst themselves, and all the strings not starting with 'x' will be sorted amongst themselves.

like image 52
SilentGhost Avatar answered Sep 18 '22 15:09

SilentGhost


First: stop saying "pythonic" when you mean "clean". It's just a cheesy buzzword.

Don't use terniary expressions like that; it's meant to be used as part of an expression, not as flow control. This is cleaner:

for word in words:
    if word[0] == 'x':
        list_1.append(word)
    else:
        list_2.append(word)

You can improve it a bit more--using terniary expressions like this is fine:

for word in words:
    target = list_1 if word[0] == 'x' else list_2
    target.append(word)

If words is a container and not an iterator, you could use:

list_1 = [word for word in words if word[0] == 'x']
list_2 = [word for word in words if word[0] != 'x']

Finally, we can scrap the whole thing, and instead use two sorts:

result = sorted(words)
result = sorted(result, key=lambda word: word[0] != 'x')

which first sorts normally, then uses the stable property of Python sorts to move words beginning with "x" to the front without otherwise changing the ordering.

like image 29
Glenn Maynard Avatar answered Sep 19 '22 15:09

Glenn Maynard