сортировать список вложенных кортежей по n-му элементу кортежа, используя itemgetter или более быстрый метод, чем лямбда - PullRequest
2 голосов
/ 11 марта 2019

У меня есть код, который тяжело сортирует списки вложенных кортежей, поэтому большая часть времени выполнения тратится на сортировку.operator.itemgetter ускорил простые сортировки, но, похоже, не может понять, как его реализовать для сортировки по n-му элементу вложенных кортежей, как, например, работает метод list.sort(key = lambda x: x[1][n]).

Пример данных ниже;

import random

v1 = random.sample(range(1, 100), 10)
v2 = random.sample(range(1, 100), 10)
v3 = random.sample(range(1, 100), 10)
v4 = random.sample(range(1, 100), 10)
out = zip(v1, zip(v2, v3, v4))
[(18, (68, 11, 71)),
 (72, (24, 3, 79)),
 (2, (1, 84, 69)),
 (24, (94, 79, 17)),
 (19, (67, 76, 19)),
 (44, (79, 12, 34)),
 (42, (11, 33, 92)),
 (90, (18, 52, 47)),
 (65, (73, 59, 70)),
 (95, (74, 85, 60))]

Если я хочу отсортировать по каждому кортежу второй элемент (в данном случае кортеж), я могу использовать:

import operator
out.sort(key = operator.itemgetter(1))
[(2, (1, 84, 69)),
 (42, (11, 33, 92)),
 (90, (18, 52, 47)),
 (72, (24, 3, 79)),
 (19, (67, 76, 19)),
 (18, (68, 11, 71)),
 (65, (73, 59, 70)),
 (95, (74, 85, 60)),
 (44, (79, 12, 34)),
 (24, (94, 79, 17))]

Если я хочу отсортировать по второму элементу каждого кортежа (кортеж в данном случае) И это элементы второго элемента, который я могу использовать;

out.sort(key = lambda x: x[1][1])
[(72, (24, 3, 79)),
 (18, (68, 11, 71)),
 (44, (79, 12, 34)),
 (42, (11, 33, 92)),
 (90, (18, 52, 47)),
 (65, (73, 59, 70)),
 (19, (67, 76, 19)),
 (24, (94, 79, 17)),
 (2, (1, 84, 69)),
 (95, (74, 85, 60))]

Можно ли это сделать с помощью itemgetter?Спасибо.

1 Ответ

2 голосов
/ 11 марта 2019

AFAIK, itemgetter не предоставляет такой режим. Вы можете, однако, определить свой собственный, используя, например, functools.partial и reduce:

>>> from functools import *
>>> deep_get = lambda *indices: partial(reduce, lambda x, i: x[i], indices)
>>> deep_get(1, 1)(out[0])
89
>>> sorted(out, key=deep_get(1, 1))
[(27, (56, 12, 88)),
 (71, (9, 22, 25)),
 (54, (35, 24, 93)),
 (98, (44, 31, 48)),
 (55, (37, 55, 44)),
 (65, (93, 58, 81)),
 (13, (25, 68, 78)),
 (14, (96, 70, 38)),
 (66, (50, 86, 15)),
 (33, (52, 89, 83))]

Обратите внимание, что это на медленнее , чем lambda, но, возможно, более универсально для различных уровней вложенности. Если речь идет только о скорости, вам следует просто заменить lambda на «правильную» функцию def get(x): return x[1][1], которая кажется такой же быстрой, как itemgetter (в моей системе сортировка out занимает 1,3 мкс с itemgetter (один уровень) или def get, 1,7 мкс с lambda и 3 мкс с deep_get).

def get(x): return x[1][1] # faster than lambda
sorted(out, key=get)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...