У меня есть список именованных вершин, которые могут быть довольно длинными (на данный момент он может достигать 10.000 строк, но в будущем это может быть намного больше).Сравните несколько (но не все) элементов в списке namedtuples
Мне нужно сравнить несколько элементов каждого namedtuple со всеми другими namedtuples из списка. Я ищу эффективный и общий способ для этого.
Для простоты я сделаю аналогию с пирожными, что должно облегчить понимание проблемы.
Имея список namedtuples, где каждый namedtuple является торт:
Cake = namedtuple('Cake',
['cake_id',
'ingredient1', 'ingredient2', 'ingredient3',
'baking_time', 'cake_price']
)
cake_price
Оба и baking_time
имеют важное значение. Если торты имеют одни и те же ингредиенты, я хочу удалить из списка те, которые не имеют отношения к делу. Таким образом, любой пирог (с теми же ингредиентами), который является равным или более дорогим и принимает такое же или более длительное время для выпекания, не имеет значения (ниже приведен подробный пример).
Какой был бы лучший способ сделать это?
подход
То, что я сделал до сих пор является для сортировки списка named_tuples по cake_price
и baking_time
:
sorted_cakes = sorted(list_of_cakes, key=lambda c: (c.cake_price, c.baking_time))
, а затем создать новый список, в котором я добавляю все торты, как так как ни один пирог, добавленный ранее, не имеет одинаковых ингредиентов, дешевле и быстрее выпекать.
list_of_good_cakes = []
for cake in sorted_cakes:
if interesting_cake(cake, list_of_good_cakes):
list_of_good_cakes.append(cake)
def interesting_cake(current_cake, list_of_good_cakes):
is_interesting = True
if list_of_good_cakes: #first cake to be directly appended
for included_cake in list_of_good_cakes:
if (current_cake.ingredient1 == included_cake.ingredient1 and
current_cake.ingredient2 == included_cake.ingredient2 and
current_cake.ingredient3 == included_cake.ingredient3 and
current_cake.baking_time >= included_cake.baking_time):
if current_cake.cake_price >= included_cake.cake_price:
is_interesting = False
return is_interesting
(я знаю, что наличие вложенного цикла далеко от оптимального, но я не могу думать о каком-либо другом способе сделать это ...)
Пример:
Имея
list_of_cakes = [cake_1, cake_2, cake_3, cake_4, cake_5]
где
cake_1 = Cake('cake_id'=1,
'ingredient1'='dark chocolate',
'ingredient2'='cookies',
'ingredient3'='strawberries',
'baking_time'=60, 'cake_price'=20)
cake_2 = Cake('cake_id'=2,
'ingredient1'='dark chocolate',
'ingredient2'='cookies',
'ingredient3'='strawberries',
'baking_time'=80, 'cake_price'=20)
cake_3 = Cake('cake_id'=3,
'ingredient1'='white chocolate',
'ingredient2'='bananas',
'ingredient3'='strawberries',
'baking_time'=150, 'cake_price'=100)
cake_4 = Cake('cake_id'=4,
'ingredient1'='dark chocolate',
'ingredient2'='cookies',
'ingredient3'='strawberries',
'baking_time'=40, 'cake_price'=30)
cake_5 = Cake('cake_id'=5,
'ingredient1'='dark chocolate',
'ingredient2'='cookies',
'ingredient3'='strawberries',
'baking_time'=10, 'cake_price'=80)
Ожидаемый результат был бы:
list_of_relevant_cakes = [cake_1, cake_3, cake_4, cake_5]
- cake_1 является самым дешевым (и самым быстрым из той же цены) -> В
- cake_2 имеет такую же цену, как cake1 и занимает больше времени, чтобы испечь -> OUT
- cake_3 это другой вид пироги -> в
- cake_4 дороже cake_1, но быстрее испечь -> в
- cake_5 дороже cake_1 и cake_4, но еще быстрее испечь -> в
Brilliant! Я адаптировал его к своему реальному делу. Тестируя его со списком 5330 namedtuples, разница огромна. Время работы до: '25.2s',' 14.1s', '14.8s'; время работы после: '0.04s',' 0.2s', '0.04s'. Только один вопрос, который меня смутил: как работает 'else' в' update_cluster'? Он не имеет того же отступа, что и предложение 'if', поэтому в начале я думал, что это опечатка. Затем я понял, что результаты не были правильно рассчитаны, если 'else' не был отступом, поскольку вы его написали ... – J0ANMM
Рад, что он помог :-)' else' в 'update_cluster()' прикреплен к 'for', а не 'if' ... документация для конструкции' for-else' - это [здесь] (https://docs.python.org/3/tutorial/controlflow.html#break-and-continue-statements-and-else- clauses-on-loops), и хорошая пояснительная статья [здесь] (http://python-notes.curiousefficiency.org/en/latest/python_concepts/break_else.html). По сути, он работает, если 'break' не запускается. –