Естественно отсортировать список буквенно-цифровых кортежей по первому элементу кортежа в Python - PullRequest
4 голосов
/ 27 июля 2011

A предыдущий вопрос stackoverflow объясняет, как сортировать список строк в алфавитном порядке. Я хотел бы отсортировать список кортежей по алфавиту по первому элементу кортежа.

Пример 1:

>>> sort_naturally_tuple([('b', 0), ('0', 1), ('a', 2)])
[('0', 1), ('a', 2), ('b', 0)]

Пример 2:

>>> sort_naturally_tuple([('b10', 0), ('0', 1), ('b9', 2)])
[('0', 1), ('b9', 2), ('b10', 0)]

Обновление: Чтобы подчеркнуть буквенно-цифровой фактор, просмотрите пример 2.

Ответы [ 4 ]

5 голосов
/ 27 июля 2011

Использование второго ответа из другого вопроса, обобщенного для поддержки любого метода элемента, в качестве основы для получения ключа:

import re
from operator import itemgetter

def sorted_nicely(l, key):
    """ Sort the given iterable in the way that humans expect."""
    convert = lambda text: int(text) if text.isdigit() else text
    alphanum_key = lambda item: [ convert(c) for c in re.split('([0-9]+)', key(item)) ]
    return sorted(l, key = alphanum_key)


print sorted_nicely([('b10', 0), ('0', 1), ('b9', 2)], itemgetter(0))

Это то же самое, что и ответ, за исключением обобщенного использования любой вызываемый в качестве операции над элементом. Если бы вы просто хотели сделать это для строки, вы бы использовали lambda item: item, если вы хотите сделать это для списка, кортежа, наложения или набора, вы бы использовали operator.itemgetter(key_or_index_you_want), или если вы хотите сделать это на экземпляре класса вы можете использовать operator.attrgetter('attribute_name_you_want').

Даёт

[('0', 1), ('b9', 2), ('b10', 0)]

для вашего примера # 2.

4 голосов
/ 27 июля 2011

Кортежи по умолчанию сортируются по элементам, начиная с первого. Так просто сделай

L = [('b', 0), ('0', 1), ('a', 2)]
L.sort()
print L
# or create a new, sorted list
print sorted([('b', 0), ('0', 1), ('a', 2)])

Вопрос, который вам понравился, касается естественной сортировки, которая отличается от обычной (буквенно-цифровой) сортировки.

Допустим, вы хотите сделать естественную сортировку только по первому элементу:

import re
def naturalize(item):
    # turn 'b10' into ('b',10) which sorts correctly
    m = re.match(r'(\w+?)(\d+)', item)
    return m.groups()
# now sort by using this function on the first element of the tuple:
print sorted(L, key=lambda tup: naturalize(tup[0]))
1 голос
/ 27 июля 2011

Как уже отмечали другие, по умолчанию сортированный будет использовать первый элемент кортежа.Если вы хотите изменить это поведение по умолчанию, вы можете указать ключ, который будет использоваться во время сравнений.

sorted([('b', 0), ('0', 1), ('a', 2)])

Будет возвращать то же, что и:

sorted([('b', 0), ('0', 1), ('a', 2)], key=lambda item: item[0])

Для сортировки по второму элементуоднако попробуйте:

sorted([('b', 0), ('0', 1), ('a', 2)], key=lambda item: item[1])
0 голосов
/ 15 января 2015

Модуль natsort делает это по умолчанию без какой-либо дополнительной работы

>>> from natsort import natsorted
>>> natsorted([('b', 0), ('0', 1), ('a', 2)])
[('0', 1), ('a', 2), ('b', 0)]
>>> natsorted([('b10', 0), ('0', 1), ('b9', 2)])
[('0', 1), ('b9', 2), ('b10', 0)]
...