2014-01-23 3 views
3

Какой самый питонический способ сравнить два неупорядоченных списка по одному или нескольким их атрибутам? Мне было бы интересно узнать, есть ли питонический способ узнать, есть ли для каждого элемента списка A элемент в списке B, где элемент из списка A и элемент в списке B соответствуют указанному атрибуту.Pythonic Способ сравнения двух неупорядоченных списков по атрибутам

В моем примере, у меня есть два ZIP-файла в модульном тесте и вы хотите проверить, соответствуют ли файлы, но я действительно ищу хорошее общее решение для своего личного набора инструментов. Это была моя первая попытка:

with ZipFile('A.zip') as old: 
with ZipFile('B.zip') as new: 
oldFileInfo = old.infolist() 

allFound = True 
for info in new.infolist(): 
    matches = [item for item in oldFileInfo if item.CRC == info.CRC and \ 
       basename(item.filename) == basename(info.filename) ] 
    if len(matches) == 0: 
     allFound = False 
     break 

Может быть, это тривиально, но я еще не нашел хороший способ, как это сделать.

Привет Майкл

+0

Что-то не так с отступом. – bereal

+0

Я согласен с ними как с fedorSmirnov, так и с редкими в своих ответах. Один берет, насколько вы заботитесь о производительности, а другой - с удобочитаемостью. Что для вас важнее? Если эта часть кода используется слишком много, я бы выбрал первый вариант. –

+1

@ ArthurJulião Я не думаю, что сортировка и сравнение списков будут быстрее. Оба решения - O (n * log n), но 'issubset' - это что-то, реализованное внутри C, а пользовательская итерация - в Python. Возможно, стоит проверить. – bereal

ответ

2

Легко, вы должны использовать наборы:

if set(list1).difference(set(list2)): 
    # lists are different 
    # different_items = set(list1).difference(set(list2)) 
    pass 
else: 
    # lists are the same 
    pass 

Вы можете преобразовать структуру итерируемыми или списков:

list1 = [(i.CRC, basename(i.filename)) for i in old.infolist()] 
list2 = [(i.CRC, basename(i.filename)) for i in new.infolist()] 
+1

спасибо. Это было очень ясно и просто. - Но другие тоже неплохие. – Michael

+0

Это не так, потому что [1,2,3,3,3,3] не должно быть равно [2,3,1] – polvoazul

+1

@polvoazul Я так не думаю, пожалуйста, прочитайте вопрос. Все элементы из списка A [1,2,3,3,3,3] представлены в списке B [2,3,1]. И да, все элементы из списка B присутствуют в списке A тоже. Таким образом, эти списки равны в этом случае. Если вы хотите сравнить список по одному, просто используйте len (A) == len (B) как дополнительное самое верхнее условие. – Jiri

1

Один из возможных способов сделать это может быть:

def areEqual(old, new): 
    set1 = set((x.attribute1, x.attribute2) for x in old) 
    set2 = set((x.attribute1, x.attribute2) for x in new) 

    return set1 == set2 
1

Вы можете создавать наборы из старых и новых списков, а затем сравнить их:

old_set = set((item.CRC, item.filename) for item in old_info) 
new_set = set((item.CRC, item.filename) for item in new_info) 

all_match = new_set.issubset(old_set) # or old_set.issuperset(new_set) 
1

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

Смежные вопросы