пересечение наборов Python с наборами объектов - PullRequest
5 голосов
/ 28 марта 2012

Я работаю с amazon boto и у меня есть 2 списка. Список 1 содержит объекты экземпляра. Список 2 содержит объекты InstanceInfo. Оба объекта имеют атрибут с именем id. Мне нужно получить список объектов Instance, идентификатор которых существует в списке InstanceInfo.

l1 = [Instance:i-04072534, Instance:i-06072536, Instance:i-08072538, Instance:i-0a07253a, Instance:i-e68fa1d6, Instance:i-e88fa1d8, Instance:i-ea8fa1da, Instance:i-ec8fa1dc]

l2 = [InstanceInfo:i-ec8fa1dc, InstanceInfo:i-ea8fa1da, InstanceInfo:i-e88fa1d8, InstanceInfo:i-e68fa1d6]

Требуемый результат:

l3 = [Instance:i-ec8fa1dc, Instance:i-ea8fa1da, Instance:i-e88fa1d8, Instance:i-e68fa1d6]

Прямо сейчас у меня все работает:

l3= []
for a in l1  
    for b in l2:
        if a.id == b.id:
            l3.append(a)

Однако мне сказали, что я должен заменить это, используя пересечение множеств. Я смотрел на примеры, и это выглядит очень просто. Пока я не вижу примеров работы с объектами.

Я немного поигрался и теоретически могу видеть, как это работает, но может быть какой-то «расширенный» синтаксис, который я, возможно, не знаю. Я все еще изучаю Python.

Ответы [ 3 ]

8 голосов
/ 28 марта 2012

Вот что-то более быстрое, чем ответ Марцина (хотя и похожий):

ids_l1 = set(x.id for x in l1)  # All ids in list 1
intersection = [item for item in l2 if item.id in ids_l1]  # Only those elements of l2 with an id in l1

Важно предварительно рассчитать ids_l1 и не писать if item.id in set(…), поскольку набор будет восстанавливаться каждый раз (так как полное тестовое выражение переоценивается для каждого элемента item).

Наборы Python дают вам быстрые тесты на членство в элементе (in). Такие тесты намного быстрее с наборами, чем со списками (поскольку элементы списка должны читаться один за другим, тогда как элементы набора «хэшируются»).

0 голосов
/ 28 марта 2012

Ваш метод может быть относительно эффективным для небольших списков.

С наборами вам придется извлечь идентификаторы, вычислить пересечение идентификаторов, а затем собрать элементы в новый список.Что-то вроде:

set1 = set(x.id for x in l1)
set2 = set(x.id for x in l2)
intersection_ids = set1 & set2
intersection_list = [item for item in l2 if item.id in intersection_ids]

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

0 голосов
/ 28 марта 2012

Попробуйте это:

# get ids of elements in second list
l2_ids = [x.id for x in l2]
# get elements from first list that have ids in second
l3 = [x for x in l1 if x.id in l2_ids]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...