Поиск списка объектов в Python - PullRequest
71 голосов
/ 28 февраля 2009

Давайте предположим, что я создаю простой класс для работы, похожий на структуру в стиле C, для хранения элементов данных. Я пытаюсь выяснить, как искать в списке объектов объекты с атрибутом, равным определенному значению. Ниже приведен тривиальный пример, иллюстрирующий то, что я пытаюсь сделать.

Например:

class Data:
    pass

myList = []

for i in range(20):
    data = Data()
    data.n = i
    data.n_squared = i * i
    myList.append(data)

Как мне выполнить поиск в списке myList, чтобы определить, содержит ли он элемент с n == 5?

Я гуглил и искал документы по Python, и думаю, что смогу сделать это с пониманием списка, но я не уверен. Я мог бы добавить, что мне, кстати, приходится использовать Python 2.4.3, поэтому любые новые функции gee-whiz 2.6 или 3.x мне недоступны.

Ответы [ 8 ]

98 голосов
/ 28 февраля 2009

Вы можете получить список из всех соответствующих элементов с пониманием списка:

[x for x in myList if x.n == 30]  # list of all elements with .n==30

Если вы просто хотите определить, содержит ли список какой-либо элемент, который соответствует, и сделать это (относительно) эффективно, вы можете сделать

def contains(list, filter):
    for x in list:
        if filter(x):
            return True
    return False

if contains(myList, lambda x: x.n == 3)  # True if any element has .n==3
    # do stuff
59 голосов
/ 28 февраля 2009

Простой, элегантный и мощный:

Выражение-генератор в соединении со встроенным… (python 2.5 +)

any(x for x in mylist if x.n == 10)

Использует встроенный Python any(), который определяется следующим образом:

любой (повторяемый) -> Верните True, если какой-либо элемент итерируемого равен true. Эквивалентно:

def any(iterable):
    for element in iterable:
        if element:
            return True
    return False
42 голосов
/ 28 февраля 2009

Просто для полноты давайте не забудем простейшую вещь, которая могла бы сработать:

for i in list:
  if i.n == 5:
     # do something with it
     print "YAY! Found one!"
31 голосов
/ 28 февраля 2009
[x for x in myList if x.n == 30]               # list of all matches
[x.n_squared for x in myList if x.n == 30]     # property of matches
any(x.n == 30 for x in myList)                 # if there is any matches
[i for i,x in enumerate(myList) if x.n == 30]  # indices of all matches

def first(iterable, default=None):
  for item in iterable:
    return item
  return default

first(x for x in myList if x.n == 30)          # the first match, if any
27 голосов
/ 28 февраля 2009
filter(lambda x: x.n == 5, myList)
8 голосов
/ 28 февраля 2009

Вы можете использовать in для поиска элемента в коллекции и понимание списка для извлечения интересующего вас поля. Это (работает для списков, наборов, кортежей и всего, что определяет __contains__ или __getitem__).

if 5 in [data.n for data in myList]:
    print "Found it"

Смотри также:

3 голосов
/ 01 марта 2009

Рассмотрите возможность использования словаря:

myDict = {}

for i in range(20):
    myDict[i] = i * i

print(5 in myDict)
3 голосов
/ 28 февраля 2009

Вы должны добавить __eq__ и __hash__ метод к вашему классу Data, он мог бы проверить, равны ли атрибуты __dict__ (те же свойства), а затем, если их значения равны.

Если вы сделали это, вы можете использовать

test = Data()
test.n = 5

found = test in myList

Ключевое слово in проверяет, находится ли test в myList.

Если вы хотите только n свойство в Data, вы можете использовать:

class Data(object):
    __slots__ = ['n']
    def __init__(self, n):
        self.n = n
    def __eq__(self, other):
        if not isinstance(other, Data):
            return False
        if self.n != other.n:
            return False
        return True
    def __hash__(self):
        return self.n

    myList = [ Data(1), Data(2), Data(3) ]
    Data(2) in myList  #==> True
    Data(5) in myList  #==> False
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...