2009-02-28 2 views
50

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

Например:

class Data: 
    pass 

myList = [] 

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

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

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

+0

Возможно непреднамеренное причуда вашего примера: MyList = [Data() п == 0 п, Data() = 1.. , ...], где data.n будет назначаться диапазоном() и data.n будет индексом в myList. Поэтому вы можете вытащить любой экземпляр Data(), просто указав myList на значение индекса. Конечно, вы могли бы позже модифицировать myList [0] .n = 5.2 или что-то в этом роде. И пример, возможно, был слишком упрощен. – DevPlayer

ответ

66

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

[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 
+19

или любой (custom_filter (x) для x в myList, если x.n == 30), который является вашей функцией «содержит» как встроенный. – nosklo

+0

Ошибка синтаксиса на nosklo - нужен дополнительный набор() вокруг генератора. – gahooa

+0

Не так. Попробуй и посмотри. –

1

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

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

test = Data() 
test.n = 5 

found = test in myList 

The 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 
25
[x for x in myList if x.n == 30]    # list of all 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 
+0

Это хороший ответ из-за «первого» метода, который, вероятно, является наиболее распространенным вариантом использования. – galarant

36

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

for i in list: 
    if i.n == 5: 
    # do something with it 
    print "YAY! Found one!" 
24
filter(lambda x: x.n == 5, myList) 
+23

для тех, кто хочет изучить Python, понимание лямбда является основным. – vartec

+1

Ну, да и нет - со списком и сортировкой ключевых функций, таких как operator.attrgetter, я почти никогда не использую 'lambda'. –

7

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

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

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

46

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

Выражение генератор в конъюнкции с встроенной командой ... (Пыть хон 2.5+)

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

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

любого (итерация)-> Возвращает True, если любой элемент Iterable верно. Эквивалент:

def any(iterable): 
    for element in iterable: 
     if element: 
      return True 
    return False 
+0

Ницца. FYI вы можете сделать любой (x для x в mylist, если x.n == 10), чтобы сохранить некоторые parens (также == not =). –

3

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

myDict = {} 

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

print(5 in myDict) 
+0

Или: d = dict ((i, i * i) для i в диапазоне (20)) – hughdbrown

+0

Он решает тривиальную проблему, которую я использовал для иллюстрации моего вопроса, но на самом деле не решал мой вопрос с корнем. Ответ, который я искал (5+ лет назад), был понятным в списке. :) – m0j0

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