Фильтр Python список диктов, чтобы вернуть один дикт - PullRequest
0 голосов
/ 31 октября 2018

У меня есть список диктов, и мне нужно отфильтровать по ключу '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'}}

Ответы [ 5 ]

0 голосов
/ 01 ноября 2018
def find_company_with_name(name):
    return next(c for c in companies if c.values()[0]['name'] == name)

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

0 голосов
/ 31 октября 2018

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

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]
0 голосов
/ 31 октября 2018

Я всегда любил делать вещи более читабельными, чем пытаться играть в гольф-код - - хотя иногда это тоже весело :)

При этом мы можем просто пройтись по каждому элементу в вашей компании и найти целевое имя, а затем мы вернем информацию этой компании:

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'}}

Чтобы быть чуть ближе к тому, что вы хотели, мы можем предоставить метод фильтрации util и фильтр как таковой:

метод:

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'}}]
0 голосов
/ 31 октября 2018

Попробуйте это:

[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'}}
]
0 голосов
/ 31 октября 2018

Как то так. Для циклов можно улучшить хотя

company_dict = {}
for company in companies:
    for c in company:
        company_dict[c] = company.get(c)


print (company_dict)
...