Сортировать список кортежей по определенному элементу и по подстроке этого элемента - PullRequest
0 голосов
/ 08 декабря 2018

Я пытаюсь отсортировать список кортежей.Они в следующем формате:

("First Last", 3, 0)

Или другими словами:

(string, int, int)

Я хочу отсортировать по строковому значению (первый элемент кортежа).Я нашел способ сортировки списка кортежей по определенному элементу из этого удивительного ответа: https://stackoverflow.com/a/3121985/8887398

Это был мой код:

# Yes, I do want to start from element 1 btw
myList[1:].sort(key=lambda tup: tup[0])

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

("George", 8, 3)

Затем я добавил фамилии, такие как:

("George Manning", 8, 3)

Он больше не сортируется правильно, поэтому я попробовал это:

myList[1:].sort(key=lambda tup: (tup[0].split(" ")[1]))

Я был так уверен, что это сработает.Это не так.Я в замешательстве, так как знаю, что мой метод split правильно извлекает фамилию из отладки.Что я делаю неправильно?Как мне отсортировать мой список по фамилии?

Вот пример.Да, это фальшивые имена:

myList = [
    ("NAME", "SOME LABEL 1", "SOME LABEL 2"),
    ("Kevin Lee", 45, 4),
    ("John Bowes", 35, 2),
    ("George Smith", 8, 3),
    ("Gina Marnico", 40, 3),
    ("Alice Gordon", 48, 7),
    ("Lee Jackson", 49, 7),
    ("Adam Hao", 50, 4),
    ("Adrian Benco", 23, 2),
    ("Jessica Farner", 43, 20),
    ("Greg Hyde", 34, 20),
    ("Ryan Valins", 39, 7),
    ("Gary Funa", 49, 7),
    ("Sam Tuno", 15, 4),
    ("Katy Sendej", 30, 2),
    ("Jessica Randolf", 44, 8),
    ("Gina Gundo", 47, 30)
]

myList[1:].sort(key=lambda tup: (tup[0].split(" ")[1]))

Я пропускаю первое значение, потому что оно обозначает информацию.Я хочу, чтобы этот элемент оставался прежним, а остальная часть списка сортировалась по фамилии.

Ответы [ 4 ]

0 голосов
/ 08 декабря 2018

Выражение myList[1:] создает отдельный объект списка с буфером, отличным от буфера myList.Вы успешно сортируете этот объект на месте, но результат удаляется, не затрагивая оригинал myList.

У вас есть несколько вариантов.Самое простое - просто сохранить отсортированный объект и либо заново вставить его, либо просто прикоснуться к первому элементу:

data = myList[1:]
data.sort(key=lambda x: x[0].split()[::-1])
myList[1:] = data

или

...
myList = [myList[0]] + data

или

...
myList = myList[:1] + data

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

myList[1:] = sorted(myList[1:], key=lambda x: x[0].split()[::-1]))

Или

myList = [myList[0]] + sorted(myList[1:], key=lambda x: x[0].split()[::-1]))

Или

myList = myList[:1] + sorted(myList[1:], key=lambda x: x[0].split()[::-1]))

Здесь вы можете даже использовать шаблон wrap-sort-unwrap.Оболочкой будет флаг, указывающий, является ли элемент заголовком, позволяющий сортировать весь список сразу, сохраняя заголовок там, где он находится.Я не рекомендую этот подход здесь, потому что он излишний и менее разборчивый, чем альтернативы.Однако этот шаблон может оказаться полезным в других местах:

myList = [x[1] for x in sorted(enumerate(myList), key=lambda x: (bool(x[0]), x[1][0].split()[::-1]))]

Все эти проблемы исчезнут, если вы измените дизайн программы, чтобы сохранить однородные данные в вашем списке.Допустим, вы получили свой список из файла CSV.Вы всегда можете сделать следующее:

myHeader, *myList = myList
myList.sort(...)

Первая строка - это простой синтаксический сахар для удаления первого элемента и повторной упаковки остальных.По сути, это эквивалентно

myHeader, myList = myList[0], myList[1:]

Во всех случаях я бы рекомендовал использовать .split()[::-1] или по крайней мере .split()[-1] в ключе, а не .split(' ')[1].Первый вариант позволит вам сортировать по имени, если фамилия совпадает.Он основан на лексикографическом сравнении последовательностей.Второй вариант будет использовать последний элемент имени в качестве ключа сортировки, что делает его устойчивым к отчествам и одиночным именам.

0 голосов
/ 08 декабря 2018

Удалите строку маркировки, и она заработает:

    myList.sort(key=lambda tup: (tup[0].split(" ")[1]))

Результат:

    ('Adrian Benco', 23, 2) 
    ('John Bowes', 35, 2) 
    ('Jessica Farner', 43, 20) 
    ('Gary Funa', 49, 7) 
    ('Alice Gordon', 48, 7) 
    ('Gina Gundo', 47, 30) 
    ('Adam Hao', 50, 4)
    ('Greg Hyde', 34, 20) 
    ('Lee Jackson', 49, 7) 
    ('Kevin Lee', 45, 4)
    ('Gina Marnico', 40, 3)
    ('Jessica Randolf', 44, 8) 
    ('Katy Sendej', 30, 2) 
    ('George Smith', 8, 3) 
    ('Sam Tuno', 15, 4) 
    ('Ryan Valins', 39, 7)
0 голосов
/ 08 декабря 2018

[myList[0]] + sorted(myList[1:], key=lambda t: t[0].split(' ')[1])

Вы также можете не сортировать по месту и удерживать строку метки постоянной.

0 голосов
/ 08 декабря 2018

Это может сработать, если вы хотите отсортировать по фамилии:

a = myList[1:]
a.sort(key=lambda tup: tup[0].split(" ")[1])
myList[1:] = a

Результат:

[
    ('NAME', 'SOME LABEL 1', 'SOME LABEL 2'),
    ('Adrian Benco', 23, 2),
    ('John Bowes', 35, 2),
    ('Jessica Farner', 43, 20),
    ('Gary Funa', 49, 7),
    ('Alice Gordon', 48, 7),
    ('Gina Gundo', 47, 30),
    ('Adam Hao', 50, 4),
    ('Greg Hyde', 34, 20),
    ('Lee Jackson', 49, 7),
    ('Kevin Lee', 45, 4),
    ('Gina Marnico', 40, 3),
    ('Jessica Randolf', 44, 8),
    ('Katy Sendej', 30, 2),
    ('George Smith', 8, 3),
    ('Sam Tuno', 15, 4),
    ('Ryan Valins', 39, 7)
]

Если вы хотите отсортировать по фамилии и тогда сначала вы можете сделать это:

a.sort(key=lambda tup: list(reversed(tup[0].split(" "))))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...