У меня есть список dict, и мне нужно отфильтровать ключ «name» (значения гарантированно уникальны) во вложенном dict, чтобы вернуть один dict. У меня есть рабочее решение, но я подумал, что будут более эффективные / элегантные / питонические методы.
Я пробовал понимать словарь, но не мог понять, как он будет перебирать список
Решения для 2.7+ и 3 будут оценены.
companies=[
{
'c01': {
'name':'x',
'address': '1 st'
}
},
{
'c02': {
'name':'y',
'address': '2 st'
}
},
]
company = [ c for c in companies if c.values() == [ v for v in c.values() if v['name']=='x'] ][0]
print company
Выход:
{'c01': {'name': 'x', 'address': '1 st'}}
пожалуйста, поясните подробнее, что вы хотите получить. также выражение company = x == y принимает только истинное или ложное значение, но не любое другое значение.
Я предполагаю, что OP вставил только часть списка и, следовательно, зафиксировал индекс с помощью loans
. Если это не так, приведенный выше код завершится ошибкой индексации.
Что-то вроде этого. Циклы For можно улучшить, хотя
company_dict = {}
for company in companies:
for c in company:
company_dict[c] = company.get(c)
print (company_dict)
Мне всегда нравилось делать вещи более читабельными, чем пытаться играть в кодовый гольф - - хотя иногда бывает и весело :)
При этом мы можем просто перебирать каждый элемент в ваших компаниях и искать целевое имя, а затем возвращать информацию об этой компании:
def get_target_company_info(companies):
TARGET_NAME = 'loans'
for company in companies:
company_id = company.keys()[0]
name_val = company.get(company_id).get('name')
if name_val == TARGET_NAME:
return company
return None
company = get_target_company_info(companies)
print company
выход:
{'c01': {'name': 'loans', 'address': '1 st'}}
Чтобы быть немного ближе к тому, что вы хотели, мы можем предоставить метод фильтрации и фильтр как таковой:
метод:
TARGET_NAME = 'loans'
def is_relevant_company(company):
company_id = company.keys()[0]
name_val = company.get(company_id).get('name')
return company if name_val == TARGET_NAME else None
фильтр:
relevant_companies = filter(None, [is_relevant_company(company) for company in companies])
выход:
[{'c01': {'name': 'loans', 'address': '1 st'}}]
Попробуй это:
[c for c in companies if any(['name' in c[x] and c[x]['name']=='x' for x in c])]
это отфильтровывает все компании с name == "x"
, и вывод для вашего примера будет:
[
{'c01': {'name': 'x', 'address': '1 st'}}
]
Вам нужен только один словарь, поэтому нет необходимости в понимании списка. Просто переберите компании, используя цикл, и прервитесь, когда найдете совпадение (при условии, что ваша структура данных идентична для каждого элемента в списке).
target = 'loans'
result = {}
for company in companies:
data = company.values()[0] # There is only one name & address per company record.
if data['name'] == target: # Check if the company name matches the target.
result = data # If so, set the result to the data for the target company.
break # Then break from the loop, as you've found the only match.
Для python 3 вам необходимо внести следующие изменения:
data = list(company.values())[0]
def find_company_with_name(name):
return next(c for c in companies if c.values()[0]['name'] == name)
Использование выражения генератора более эффективно, чем понимание списка, поскольку оно может прекратить поиск, как только найдет совпадение, без создания остальной части списка.
В ваших данных выборки нет
'loans'
; на что именно вы надеетесь, что ваш код будет делать?