Подтвердить что ты не робот

Поиск Python в списках списков

У меня есть список списков двух элементов и вам нужно искать вещи в нем.

Если список:

list =[ ['a','b'], ['a','c'], ['b','d'] ]

Я могу легко найти пару, выполнив

['a','b'] in list

Теперь, есть ли способ увидеть, есть ли у меня пара, в которой строка присутствует только во второй позиции? Я могу это сделать:

for i in range (0, len(list)):
    if list[i][1]==search:
       found=1

Но есть ли лучший способ без цикла for? Мне не нужно знать i или продолжать цикл после его обнаружения.

4b9b3361

Ответ 1

У вас всегда будет цикл: кто-то может прийти с умным однострочным лайнером, который скрывает цикл в вызове map() или аналогичный, но он всегда будет там.

Мои предпочтения всегда будут иметь чистый и простой код, если только производительность не является основным фактором.

Здесь возможно более Pythonic версия вашего кода:

data = [['a','b'], ['a','c'], ['b','d']]
search = 'c'
for sublist in data:
    if sublist[1] == search:
        print "Found it!", sublist
        break
# Prints: Found it! ['a', 'c']

Он вырывается из цикла, как только находит совпадение.

(У вас есть опечатка, кстати, в ['b''d'].)

Ответ 2

Здесь питонический способ сделать это:

data = [['a','b'], ['a','c'], ['b','d']]
search = 'c'
any(e[1] == search for e in data)

Или... ну, я не собираюсь утверждать, что это "один истинный питонический способ", чтобы сделать это, потому что в какой-то момент становится немного субъективным, что такое Pythonic, а что нет, или какой метод более Pythonic, чем другой. Но использование any() - это, безусловно, более типичный стиль Python, чем цикл for, как, например, Ответ RichieHindle,

Конечно, в реализации any существует скрытый цикл, хотя он выходит из цикла, как только он находит совпадение.


Так как мне было скучно, я сделал выбор времени script, чтобы сравнить производительность различных предложений, изменив некоторые из них по мере необходимости, чтобы сделать API одинаковым. Теперь мы должны помнить, что самый быстрый не всегда лучший, и быть быстрым, определенно, не то же самое, что быть Pythonic. При этом результаты... странные. Видимо, циклы for очень быстрые, чего я не ожидал, поэтому я бы взял их с солью, не понимая, почему они вышли так, как они делают.

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

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

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

Это те, которые сохраняют свое первоначальное время, когда список расширен. Остальное, что нет,

  1. Цикл for из исходного вопроса, на 1,24 мкс
  2. Первое предложение Terence Honles, которое создает список в 7.49 мкс
  3. Ответ Пьер-Люка Бедарда (последний кодовый блок), в 8.12 мкс
  4. Ответ Маркуса, в 10.27 мкс
  5. jojo answer, в 19.87 мкс
  6. И наконец user27221 answer с использованием вложенных списков в 60.59 мкс

Ответ 3

>>> the_list =[ ['a','b'], ['a','c'], ['b''d'] ]
>>> any('c' == x[1] for x in the_list)
True

Ответ 4

выше всего выглядят хорошо

но вы хотите сохранить результат?

если так...

вы можете использовать следующие

result = [element for element in data if element[1] == search]

то простой

len(result)

позволяет узнать, что-нибудь найдено (и теперь вы можете делать что-то с результатами)

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

если вы знаете, что все элементы - это заданная длина, которую вы также можете сделать:

any(second == search for _, second in data)

или для len (данные [0]) == 4:

any(second == search for _, second, _, _ in data)

... и я бы рекомендовал использовать

for element in data:
   ...

вместо

for i in range(len(data)):
   ...

(для будущих целей, если вы не хотите сохранять или использовать "i", и просто чтобы вы знали '0' не требуется, вам нужно всего лишь использовать полный синтаксис, если вы начинаете при ненулевом значении)

Ответ 5

>>> my_list =[ ['a', 'b'], ['a', 'c'], ['b', 'd'] ]
>>> 'd' in (x[1] for x in my_list)
True

Редактирование для добавления:

Оба Дэвида отвечают с помощью any, а мой, используя в, заканчиваются, когда они находят соответствие, поскольку мы используем выражения генератора. Вот тест с использованием бесконечного генератора, чтобы показать, что:

def mygen():
    ''' Infinite generator '''
    while True:
        yield 'xxx'  # Just to include a non-match in the generator
        yield 'd'

print 'd' in (x for x in mygen())     # True
print any('d' == x for x in mygen())  # True
# print 'q' in (x for x in mygen())     # Never ends if uncommented
# print any('q' == x for x in mygen())  # Never ends if uncommented

Мне просто нравится использовать в вместо == и любой.

Ответ 6

Как насчет:

list =[ ['a','b'], ['a','c'], ['b','d'] ]
search = 'b'

filter(lambda x:x[1]==search,list)

Это вернет каждый список в список списков, при этом второй элемент будет равен поиску.

Ответ 7

У Маркуса есть один способ избежать использования слова for - здесь другой, который должен иметь гораздо лучшую производительность для длинных the_list s...:

import itertools
found = any(itertools.ifilter(lambda x:x[1]=='b', the_list)

Ответ 8

Ничего плохого в использовании gen exp, но если целью является встраивание цикла...

>>> import itertools, operator
>>> 'b' in itertools.imap(operator.itemgetter(1), the_list)
True

Должен быть и самым быстрым.

Ответ 9

k старый пост, но никто не использует выражение списка для ответа: P

list =[ ['a','b'], ['a','c'], ['b','d'] ]
Search = 'c'

# return if it find in either item 0 or item 1
print [x for x,y in list if x == Search or y == Search]

# return if it find in item 1
print [x for x,y in list if y == Search]

Ответ 10

>>> the_list =[ ['a','b'], ['a','c'], ['b','d'] ]
>>> "b" in zip(*the_list)[1]
True

zip() объединяет множество списков и группирует элементы по индексу, эффективно переносив матрицу списка списков. Звездочка берет содержимое the_list и отправляет его в zip в качестве аргументов, поэтому вы эффективно передаете три списка отдельно, что хочет zip. Осталось только проверить, есть ли "b" (или что-то еще) в списке, состоящем из элементов с интересующим вас индексом.

Ответ 11

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

list =[ ['a','b'], ['a','c'], ['b','d'] ]
search = 'c'
any([ (list.index(x),x.index(y)) for x in list for y in x if y == search ] )

Ответ 12

Я искал глубокую находку для словарей и не нашел ее. Основываясь на этой статье, я смог создать следующее. Спасибо и наслаждайтесь!

def deapFind( theList, key, value ):
    result = False
    for x in theList:
        if( value == x[key] ):
            return True
    return result

theList = [{ "n": "aaa", "d": "bbb" }, { "n": "ccc", "d": "ddd" }]
print 'Result: ' + str (deapFind( theList, 'n', 'aaa'))

Я использую == вместо оператора in, поскольку возвращает true для частичных совпадений. IOW: поиск aa по n-значению возвращает true. Я не думаю, что это было бы желательно.

НТН

Ответ 13

Ниже приведен простой способ найти, где именно находится элемент в списке.

for i in range (0,len(a)):
sublist=a[i]
for i in range(0,len(sublist)):
    if search==sublist[i]:
        print "found in sublist "+ "a"+str(i)