Более питонский способ написать это выражение? - PullRequest
8 голосов
/ 02 ноября 2010

Я должен взять список слов и отсортировать его, за исключением того, что мне нужно сгруппировать все строки, начинающиеся с 'x'.

Вот что я получил:

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)

Но я чувствую, что есть гораздо более элегантный способ сделать это ...

РЕДАКТИРОВАТЬ

Пример: ['mix', 'xyz', 'apple', 'xanadu', 'aardvark'] выход ['xanadu', 'xyz', 'aardvark', 'apple', 'mix'].

Ответы [ 8 ]

41 голосов
/ 02 ноября 2010
>>> words = ['xoo', 'dsd', 'xdd']
>>> sorted(words, key=lambda x: (x[0] != 'x', x))
['xdd', 'xoo', 'dsd']

Объяснение: функция ключа возвращает пару (кортеж).Первый элемент - False или True, в зависимости от того, является ли первый символ в строке 'x'.False сортирует до True, поэтому строки, начинающиеся с 'x', будут первыми в отсортированном выводе.Второй элемент в кортеже будет использоваться для сравнения двух одинаковых элементов в первом элементе, поэтому все строки, начинающиеся с 'x', будут отсортированы между собой, а все строки, не начинающиеся с 'x', будут отсортированымежду собой.

9 голосов
/ 02 ноября 2010

Первое: перестаньте говорить «питон», когда вы имеете в виду «чистый».Это просто глупое модное слово.

Не используйте подобные троичные выражения;он предназначен для использования как часть выражения, а не как управление потоком.Это чище:

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

Вы можете улучшить его немного больше - используйте троичные выражения, как это хорошо:

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

Если words является контейнером, а не итератором, вы можете использовать:

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

Наконец, мы можем удалить все целиком и вместо этого использовать две сортировки:

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

, которая сначала сортируется нормально, затем использует свойство stable Pythonсортирует для перемещения слов, начинающихся с «x», на передний план без изменения порядка.

6 голосов
/ 02 ноября 2010
words = ['xoo', 'dsd', 'xdd']
list1 = [word for word in words if word[0] == 'x']
list2 = [word for word in words if word[0] != 'x']
5 голосов
/ 03 ноября 2010

Следует отметить, что sorted был добавлен в Python 2.4. Если вам нужна более короткая версия, которая немного чище и несколько более обратно совместима, вы можете использовать функцию .sort() непосредственно из list. Следует также отметить, что пустые строки будут вызывать исключение при использовании синтаксиса индексации массива стиля x[0] в этом случае (как и во многих примерах). .startswith() следует использовать вместо правильно используется в ответе Тони Вейялайнена .

>>> words = ['mix', 'xyz', '', 'apple', 'xanadu', 'aardvark']
>>> words.sort(key=lambda x: (not x.startswith('x'), x))
>>> words
['xanadu', 'xyz', '', 'aardvark', 'apple', 'mix']

Единственный недостаток в том, что вы мутируете с данным объектом. Это можно исправить, предварительно разрезав список.

>>> words = ['mix', 'xyz', '', 'apple', 'xanadu', 'aardvark']
>>> new_words = words[:]
>>> new_words.sort(key=lambda x: (not x.startswith('x'), x))
>>> new_words
['xanadu', 'xyz', '', 'aardvark', 'apple', 'mix']
>>> words
['mix', 'xyz', '', 'apple', 'xanadu', 'aardvark']
2 голосов
/ 02 ноября 2010

Для повторной отправки кода варианта SilenGhosts (не стесняйтесь копировать, SilentGhost) в виде кода без журнала командной строки

notinorder = ['mix', 'xyz', '', 'apple', 'xanadu', 'aardvark']
print sorted(notinorder, key = lambda x: (not x.startswith('x'), x))
2 голосов
/ 02 ноября 2010
words = ['xoo', 'dsd', 'xdd']
list1=filter(lambda word:word[0]=='x',words)
list2=filter(lambda word:word[0]!='x',words)
1 голос
/ 02 ноября 2010
>>> x = ['abc', 'xyz', 'bcd', 'xabc']
>>> y = [ele for ele in x if ele.startswith('x')]
>>> y
['xyz', 'xabc']
>>> z = [ele for ele in x if not ele.startswith('x')]
>>> z
['abc', 'bcd']
0 голосов
/ 03 ноября 2010

Более того, в соответствии с исходным решением:

l1=[]
l2=[]
for w in sorted(words):
    (l1 if w[0] == 'x' else l2).append(w)
l1.extend(l2)
return l1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...