Как я могу изменить этот список так, чтобы все p's отображались в начале, q's в конце, а значения между ними были отсортированы в алфавитном порядке?
l = ['f','g','p','a','p','c','b','q','z','n','d','t','q']
Итак, я бы хотел иметь:
['p','p','a','b','c','d','f','g','n','t','z','q','q']






Используйте параметр key в отсортированный:
l = ['f','g','p','a','p','c','b','q','z','n','d','t','q']
def key(c):
if c == 'q':
return (2, c)
elif c == 'p':
return (0, c)
return (1, c)
result = sorted(l, key=key)
print(result)
Вывод
['p', 'p', 'a', 'b', 'c', 'd', 'f', 'g', 'n', 't', 'z', 'q', 'q']
Вы можете использовать sorted со следующим key:
sorted(l, key = lambda s: (s!='p', s=='q', s))
['p', 'p', 'a', 'b', 'c', 'd', 'f', 'g', 'n', 't', 'z', 'q', 'q']
Объяснение
Чтобы лучше понять, как это работает, следующее понимание списка нацелено на воспроизведение того, что возвращается функцией lambda, определенной в аргументе key, до проведения сравнений:
t = [(s!='p', s=='q', s) for s in pl]
print(t)
[(True, False, 'f'),
(True, False, 'g'),
(False, False, 'p'),
(True, False, 'a'),
(False, False, 'p'),
(True, False, 'c'),
(True, False, 'b'),
(True, True, 'q'),
(True, False, 'z'),
(True, False, 'n'),
(True, False, 'd'),
(True, False, 't'),
(True, True, 'q')]
Затем это будет key, который будет использоваться для сортировки элементов в списке, как указано в документация:
The value of the key parameter should be a function that takes a single argument and returns a key to use for sorting purposes.
Итак, учитывая False = 0 и True = 1, при сортировке этого списка кортежей результат будет следующим:
sorted(t)
[(False, False, 'p'),
(False, False, 'p'),
(True, False, 'a'),
(True, False, 'b'),
(True, False, 'c'),
(True, False, 'd'),
(True, False, 'f'),
(True, False, 'g'),
(True, False, 'n'),
(True, False, 't'),
(True, False, 'z'),
(True, True, 'q'),
(True, True, 'q')]
@ScottBoston нет, он возвращает кортеж (bool, bool, str)
@ juanpa.arrivillaga А ... Хорошо. Думаю, я понимаю. Я собираюсь немного поиграть с этим, чтобы закрепить это в моей голове. Спасибо.
Итак, сначала идет (Ложь, Ложь), а в конце - (Истина, Истина). Между ними будет (Верно, Ложь)
Для тех из вас, кому нужен этот sorted([(s!='p', s=='q', s) for s in l]), он отлично наглядно показывает, что происходит.
Вы можете найти все элементы p и q, отфильтровать исходный список, а затем отсортировать:
l = ['f','g','p','a','p','c','b','q','z','n','d','t','q']
_ps, _qs = [i for i in l if i == 'p'], [i for i in l if i == 'q']
new_l = _ps+sorted(filter(lambda x:x not in {'q', 'p'}, l))+_qs
Вывод:
['p', 'p', 'a', 'b', 'c', 'd', 'f', 'g', 'n', 't', 'z', 'q', 'q']
p и q: ['p']*l.count('p') + sorted(filter({'q', 'p'}.isdisjoint, l)) + ['q']*l.count('q'), что имеет такую же временную сложность. Редактировать: От lambda тоже можно избавиться.
Просто определите соответствующую ключевую функцию:
>>> def _key(x):
... if x == 'p':
... return -1
... elif x == 'q':
... return float('inf')
... else:
... return ord(x)
...
>>> l = ['f','g','p','a','p','c','b','q','z','n','d','t','q']
>>> sorted(l, key=_key)
['p', 'p', 'a', 'b', 'c', 'd', 'f', 'g', 'n', 't', 'z', 'q', 'q']
Обратите внимание, что каждый символ отображается в целое число> = 0, поэтому мы можем просто полагаться на ord, и поскольку -1 всегда будет меньше, чем все, что возвращается ord, мы можем использовать это для p, а для q мы можем использовать бесконечность, так что он всегда будет больше, чем то, что возвращает ord.
Одна из идей - использовать словарь приоритетов с настраиваемой функцией. Это, естественно, можно расширить, если вы захотите включить дополнительные критерии.
L = ['f','g','p','a','p','c','b','q','z','n','d','t','q']
def sort_func(x):
priority = {'p': 0, 'q': 2}
return priority.get(x, 1), x
res = sorted(L, key=sort_func)
print(res)
['p', 'p', 'a', 'b', 'c', 'd', 'f', 'g', 'n', 't', 'z', 'q', 'q']
Вы также можете сохранить переднюю, середину и концы в collections.defaultdict(), а затем просто добавить все три списка в конце:
from collections import defaultdict
l = ["f", "g", "p", "a", "p", "c", "b", "q", "z", "n", "d", "t", "q"]
keys = {"p": "front", "q": "end"}
d = defaultdict(list)
for item in l:
d[keys.get(item, "middle")].append(item)
print(d["front"] + sorted(d["middle"]) + d["end"])
# ['p', 'p', 'a', 'b', 'c', 'd', 'f', 'g', 'n', 't', 'z', 'q', 'q']
Решение этого вопроса:
list = ['f','g','p','a','p','c','b','q','z','n','d','t','q'];
noOfPs = [i for i in l if i == 'p'];
noOfQs = [i for i in l if i == 'q'];
resultList= noOfPs + sorted(filter(lambda x:x not in {'q', 'p'}, l))+ noOfQs
Вы можете использовать следующую функцию lambda в качестве ключа в sorted():
l1 = sorted(l, key=lambda x: ((x == 'q') - (x == 'p'), x))
print(l1)
# ['p', 'p', 'a', 'b', 'c', 'd', 'f', 'g', 'n', 't', 'z', 'q', 'q']
Функция генерирует следующие ключи сравнения:
func = lambda x: ((x == 'q') - (x == 'p'), x)
for i in l1:
print(func(i))
Вывод:
(-1, 'p')
(-1, 'p')
(0, 'a')
(0, 'b')
...
(0, 't')
(0, 'z')
(1, 'q')
(1, 'q')
Это довольно круто. Вы можете немного объяснить? отсортированные сортировки Истина <символы <Ложь?