поиск по вложенному списку в python

1

У меня есть вложенный список кортежей из 97510 таких значений:

a = [ (1,2,3), (3,4,5), (5,4,2)]

каждое первое значение (index = 0) является уникальным, и мне нужно найти другие элементы индекса = 0, которые имеют одинаковый индекс = 1 элементы. В этом примере мне нужно найти второй и третий кортежи, где второй элемент "4" общий.

Как мне это сделать?

Теги:
list
search
nested-lists

4 ответа

4

Если вы хотите найти все совпадения:

>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> for inner in a:
...     d[inner[1]].append(inner)
... 
>>> d
defaultdict(<type 'list'>, {2: [(1, 2, 3)], 4: [(3, 4, 5), (5, 4, 2)]})
>>> d[4]
[(3, 4, 5), (5, 4, 2)]

Если вы хотите выбрать все совпадения для определенного второго значения:

>>> filter(lambda inner: inner[1] == 4, a)
[(3, 4, 5), (5, 4, 2)]

Редактировать: Как указано в комментариях, предпочтительным является понимание списка, поскольку оно более эффективно для такой работы:

>>> [inner for inner in a if inner[1] == 4]
[(3, 4, 5), (5, 4, 2)]

Использование timeit показывает, что понимание списка примерно в 2,5 раза быстрее (на моей машине в любом случае):

>>> timeit.timeit('[inner for inner in a if inner[1] == 4]', 'a=[(1,2,3), (3,4,5), (5, 4, 2)]')
2.5041549205780029
>>> timeit.timeit('filter(lambda inner: inner[1] == 4, a)', 'a=[(1,2,3), (3,4,5), (5, 4, 2)]')
6.328679084777832
  • 0
    Я бы вообще предпочел понимание списка над filter с лямбдой - [item for item from a if item[1] == 4] . Это, на мой взгляд, лучше читать.
  • 0
    @ Space_C0wb0y - да, обычно тоже. Не уверен, почему я использовал фильтр в этом ответе. Я обновил его с некоторыми примерами времени - а также лучше читать, это быстрее.
3

Вот один из способов сделать это:

>>> result = defaultdict(list)
>>> for item in a:
>>>     result[item[1]].append(item)
>>> result
defaultdict(<type 'list'>, {2: [(1, 2, 3)], 4: [(3, 4, 5), (5, 4, 2)]})

Это приведет к созданию словаря списков, в котором все элементы с одним и тем же вторым значением находятся в одном списке, с этим значением в качестве ключа.

1

Другая альтернатива:

from operator import itemgetter
from itertools import groupby

a = [ (1,2,3), (3,4,5), (5,4,2)]
b = groupby(sorted(a), itemgetter(1))
for val, group in b:
    print val, list(group)
# 2 [(1, 2, 3)]
# 4 [(3, 4, 5), (5, 4, 2)]
  • 0
    Приятно. Я всегда забываю об itertools, это то, с чем мне нужно играть больше.
  • 0
    Сначала сортируется список, а затем перебирает его. Предоставление сложности O (n log n) плюс дополнительный проход по списку. Это не эффективно.
Показать ещё 2 комментария
1

Обратите внимание, что вы также можете использовать groupby:

from itertools import groupby

data = [ (1,2,3), (3,4,5), (5,4,2)]
res = groupby(sorted(data), key=lambda x: x[1])

Отредактировано в соответствии с комментарием

Играла с проблемой и нашла еще одно решение - но не самое лучшее, но:

inputVals = [(1,2,3), (3,4,5), (5,4,2), (2,2,3), (7,3,1)]
for val in set(x[1] for x in inputVals):   
    print val, list(set(sval for sval in inputVals if sval[1] == val))
  • 0
    Это работает, только если список отсортирован по ключу.
  • 0
    Конечно, спасибо. Мой ответ был предназначен для того, чтобы просто оповестить ОП, что у него есть еще один вариант.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню