Итерация по паре итераций, отсортированных по атрибуту
Один из способов (самый быстрый?) Для итерации по паре итераций a
а также b
в отсортированном порядке, чтобы объединить их в цепочку и отсортировать итерируемо:
for i in sorted(chain(a, b)):
print i
Например, если элементами каждой итерируемой являются:
a: 4, 6, 1
b: 8, 3
тогда эта конструкция будет производить элементы в порядке
1, 3, 4, 6, 8
Однако, если итерации перебирают объекты, это сортирует объекты по их адресу в памяти. Предполагая, что каждая итерация повторяется для одного и того же типа объекта,
Каков самый быстрый способ перебора определенного атрибута объектов, отсортированных по этому атрибуту?
Что, если выбранный атрибут отличается в разных предметах? Если повторяется
a
а такжеb
оба перебирают объекты типаfoo
, который имеет атрибутыfoo.x
а такжеfoo.y
того же типа, как можно перебирать элементыa
отсортировано поx
а такжеb
отсортировано поy
?
Для примера № 2, если
a: (x=4,y=3), (x=6,y=2), (x=1,y=7)
b: (x=2,y=8), (x=2,y=3)
тогда элементы должны быть произведены в порядке
1, 3, 4, 6, 8
как прежде. Обратите внимание, что только x
атрибуты из a
и y
атрибуты из b
введите в сортировку и результат.
2 ответа
Тим Пицкер уже ответил за случай, когда вы используете один и тот же атрибут для каждой итерации. Если вы используете разные атрибуты одного и того же типа, вы можете сделать это следующим образом (используя комплексные числа в качестве готового класса, который имеет два атрибута одного типа):
В Python 2:
>>> a = [1+4j, 7+0j, 3+6j, 9+2j, 5+8j]
>>> b = [2+5j, 8+1j, 4+7j, 0+3j, 6+9j]
>>> keyed_a = ((n.real, n) for n in a)
>>> keyed_b = ((n.imag, n) for n in b)
>>> from itertools import chain
>>> sorted_ab = zip(*sorted(chain(keyed_a, keyed_b), key=lambda t: t[0]))[1]
>>> sorted_ab
((1+4j), (8+1j), (3+6j), 3j, (5+8j), (2+5j), (7+0j), (4+7j), (9+2j), (6+9j))
Так как в Python 3 zip()
возвращает итератор, нам нужно привести его к списку, прежде чем пытаться его подписать:
>>> # ... as before up to 'from itertools import chain'
>>> sorted_ab = list(zip(*sorted(chain(keyed_a, keyed_b), key=lambda t: t[0])))[1]
>>> sorted_ab
((1+4j), (8+1j), (3+6j), 3j, (5+8j), (2+5j), (7+0j), (4+7j), (9+2j), (6+9j))
Ответ на вопрос 1: Вы можете предоставить key
приписывать sorted()
, Например, если вы хотите отсортировать по объекту .name
затем используйте
sorted(chain(a, b), key=lambda x: x.name)
Что касается вопроса 2: я думаю, вам понадобится еще один атрибут для каждого объекта (например, foo.z
в соответствии с предложением Zero Piraeus), к которому sorted()
, поскольку эта функция не может определить, откуда поступил объект, который она сортирует в данный момент. В конце концов, он получает новый итератор от chain()
который не содержит никакой информации о том, является ли текущий элемент из a
или же b
,