2013-06-27 1 views
2

У меня есть большой вложенный список, и каждый список внутри вложенного списка содержит список чисел, отформатированных как float. Однако каждый отдельный список во вложенном списке одинаковый, за исключением нескольких исключений. Я хочу извлечь числа, которые являются общими для всех списков во вложенном списке. Простой пример моей проблемы показано ниже:Как найти элементы, общие для всех списков во вложенном списке?

nested_list = [[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0], 
       [2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0], 
       [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0], 
       [2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0]] 

В следующем случае, я хотел бы, чтобы извлечь следующее:

common_vals = [2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0] 

Я пытался использовать набор перекрестки, чтобы решить эту проблему, но так как я не был» t, чтобы заставить это работать на все элементы вложенного списка.

ответ

6

Вы можете использовать reduce и set.intersection:

>>> reduce(set.intersection, map(set, nested_list)) 
set([2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0]) 

Использование itertools.imap для памяти эффективного решения.

Сроки Сравнения:

>>> lis = [[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0], 
       [2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0], 
       [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0], 
       [2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0]] 
>>> %timeit set.intersection(*map(set, lis)) 
100000 loops, best of 3: 12.5 us per loop 
>>> %timeit set.intersection(*(set(e) for e in lis)) 
10000 loops, best of 3: 14.4 us per loop 
>>> %timeit reduce(set.intersection, map(set, lis)) 
10000 loops, best of 3: 12.8 us per loop 
>>> %timeit reduce(set.intersection, imap(set, lis)) 
100000 loops, best of 3: 13.1 us per loop 
>>> %timeit set.intersection(set(lis[0]), *islice(lis, 1, None)) 
100000 loops, best of 3: 10.6 us per loop 


>>> lis = [[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0], 
       [2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0], 
       [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0], 
       [2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0]]*1000 
>>> %timeit set.intersection(*map(set, lis)) 
10 loops, best of 3: 16.4 ms per loop 
>>> %timeit set.intersection(*(set(e) for e in lis)) 
10 loops, best of 3: 15.8 ms per loop 
>>> %timeit reduce(set.intersection, map(set, lis)) 
100 loops, best of 3: 16.3 ms per loop 
>>> %timeit reduce(set.intersection, imap(set, lis)) 
10 loops, best of 3: 13.8 ms per loop 
>>> %timeit set.intersection(set(lis[0]), *islice(lis, 1, None)) 
100 loops, best of 3: 8.4 ms per loop 


>>> lis = [[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0],    [2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0], 
       [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0], 
       [2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0]]*10**5 
>>> %timeit set.intersection(*map(set, lis)) 
1 loops, best of 3: 1.92 s per loop 
>>> %timeit set.intersection(*(set(e) for e in lis)) 
1 loops, best of 3: 2.17 s per loop 
>>> %timeit reduce(set.intersection, map(set, lis)) 
1 loops, best of 3: 2.14 s per loop 
>>> %timeit reduce(set.intersection, imap(set, lis)) 
1 loops, best of 3: 1.52 s per loop 
>>> %timeit set.intersection(set(lis[0]), *islice(lis, 1, None)) 
1 loops, best of 3: 913 ms per loop 

Вывод:

Steven Rumbalski-х solution явно лучше один с точки зрения эффективности.

5

Попробуйте это, это самое простое решение:

set.intersection(*map(set, nested_list)) 

Или, если вы предпочитаете использовать выражения генератора, который должен быть более эффективным решением с точки зрения использования памяти:

set.intersection(*(set(e) for e in nested_list)) 
+0

В данном случае выражение генератор включен в кортеж перед вызовом функции, так что нет никакой пользы. –

0

граф вхождений каждого элемента в наборах списков, происходящих в nested_list, если вхождение равно числу лекций в nested_list, оно является общим для всех. Вам не нужно множество преобразования, если элементы nested_list не имеют номеров повторяются в них раствор

nested_list = [[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0], 
       [2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0], 
       [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0], 
       [2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0]] 

from collections import Counter 
result = [val for val,cnt in Counter([x for t in nested_list for x in set(t)]).items() if cnt == len(nested_list)] 
print result 


# [2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0] 
6

Ashwini Чаудхари является элегантным, но может быть весьма неэффективны для больших входов, поскольку он создает множество промежуточных наборов. Если nested_list велико это сделать:

>>> set.intersection(set(nested_list[0]), *itertools.islice(nested_list, 1, None)) 
set([2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0]) 
+0

Обратите внимание, что 'nested_list [1:]' создает мелкую копию 'nested_list', чего можно избежать, используя' itertools.islice (nested_list, 1, None) '. –

+0

@SvenMarnach: Хорошая точка. Изменено использование 'itertools.islice'. Свен Марнах вернулся! –

+0

+1 Лучшее решение с точки зрения эффективности. –