2013-02-18 6 views
3

Мне нужно найти первый общий список (который представляет собой список координат в этом случае) между переменным количеством списков.python - Общие списки среди списков в списке

т.е. этот список

>>> [[[1,2],[3,4],[6,7]],[[3,4],[5,9],[8,3],[4,2]],[[3,4],[9,9]]] 

должен вернуть

>>> [3,4] 

Если проще, то я могу работать со списком всех общих списков (координат) между списками, которые содержат координаты.

Я не могу использовать наборы или словари, потому что списки не хешируются (я думаю?).

+0

ли «общий» смысл «содержащиеся в каждом списке», или «не единственный в списке»? – wim

ответ

8

Исправить, list Объекты не хешируются, потому что они изменяемы. tuple объекты хешируются (при условии, что все их элементы хешируются). Так как ваши сокровенные списки все только целые числа, что дает прекрасную возможность работать вокруг не-hashableness списков:

>>> lists = [[[1,2],[3,4],[6,7]],[[3,4],[5,9],[8,3],[4,2]],[[3,4],[9,9]]] 
>>> sets = [set(tuple(x) for x in y) for y in lists] 
>>> set.intersection(*sets) 
set([(3, 4)]) 

Здесь я даю вам набор, который содержит кортежи координат, которые присутствуют во всех подсписках , Чтобы получить список, например, вы начали с:

[list(x) for x in set.intersection(*sets)] 

делает трюк.

Чтобы устранить озабоченность по @wim, если вы действительно хотите ссылку на первого элемента на пересечении (где first определяется быть первым в lists[0]), самый простой способ, вероятно, так:

#... Stuff as before 
intersection = set.intersection(*sets) 
reference_to_first = next((x for x in lists[0] if tuple(x) in intersection), None) 

Это вернет None, если пересечение пусто.

+0

-1 Я не думаю, что это гарантирует найти _first common_ duplicate – wim

+0

+1, потому что вопрос также гласит: «Если проще, я могу работать со списком всех общих списков (координат) между списками, содержащими координаты. " – EOL

+0

@wim - достаточно справедливо. Я не видел критерии * first *. Хотя, я не уверен, что это хорошо определено. Рассмотрим '[[[1,2], [2,1]], [[2,1], [1,2]]]'. Что является первым? – mgilson

0

редактировать: Ищу любой дубликат в уплощенных списках, mgilson ответа здесь ищу дубликат общего в каждом Подсписке. Я не уверен, что вы на самом деле просят об этом, но все равно ..

Этот наивный алгоритм даст вам ссылку на первый дубликат координате встречаются:

>>> def first_dup(lll): 
... seen = [] 
... for ll in lll: 
...  for coord in ll: 
...  if coord in seen: 
...   return coord 
...  else: 
...   seen.append(coord) 
... 
>>> first_dup([[[1,2],[3,4],[6,7]],[[3,4],[5,9],[8,3],[4,2]],[[3,4],[9,9]]]) 
[3, 4] 
+0

Это не работает: вы можете попробовать 'first_dup ([[[1, 2], [ 1, 2]], [[3, 4]]]). – EOL

+0

Для меня он возвращает '[1, 2]' как и ожидалось. Разве ваше понимание того, что дубликаты вершин внутри одного подсписка не считаются или ...? – wim

+0

Хороший ответ. Я забыл упомянуть, но заранее убедился, что у меня нет дубликатов в моем списке. –

1

Если вы ищете первый список дочерних элементов, который является общим среди всех родительских списков, будет работать следующее.

def first_common(lst): 
    first = lst[0] 
    rest = lst[1:] 
    for x in first: 
     if all(x in r for r in rest): 
      return x 
+0

Это, к сожалению, алгоритмически медленное: сначала создание наборов (например, в ответе mglison) дает гораздо более быстрые тесты, чем тесты 'x in r' для каждого списка' r' и для каждого элемента 'x'. Однако это имеет то преимущество, что возвращает первый элемент 'x', найденный в' first', поэтому это может быть достаточно хорошим, в зависимости от потребностей: +1. В некоторых приложениях может быть более эффективным преобразовать элементы в 'rest' в кортежи, например, в ответе Майлсона. – EOL

0

Решение с рекурсивной функцией. :)

Это получает первый дублированный элемент.

def get_duplicated_element(array): 
    global result, checked_elements 
    checked_elements = [] 
    result = -1 
    def array_recursive_check(array): 
     global result, checked_elements 
     if result != -1: return 
     for i in array: 
      if type(i) == list: 
       if i in checked_elements: 
        result = i 
        return 
       checked_elements.append(i) 
       array_recursive_check(i) 
    array_recursive_check(array) 
    return result 

get_duplicated_element([[[1,2],[3,4],[6,7]],[[3,4],[5,9],[8,3],[4,2]],[[3,4],[9,9]]]) 
[3, 4] 
-1

вы можете добиться этого с пониманием списка:

>>> l = [[[1,2],[3,4],[6,7]],[[3,4],[5,9],[8,3],[4,2]],[[3,4],[9,9]]] 
>>> lcombined = sum(l, []) 
>>> [k[0] for k in [(i,lcombined.count(i)) for i in lcombined] if k[1] > 1][0] 
[3, 4] 
+0

Это не работает: только элементы, найденные в * all *, должны быть возвращены, а не элементы, найденные в нескольких списках. – EOL

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