Как сделать Python один лайнер для создания словаря из набора результатов - PullRequest
1 голос
/ 10 июля 2020

Что у меня есть:

d1=[{'type':'fruit','name':'apple'},{'type':'fruit','name':'orange'},{'type':'vehicle','name':'car'},{'type':'vehicle','name':'bike'}]

Что я сделал:

res=[{i['type']:i['name']} for i in d1]

Что получил:

res=>[{'fruit': 'apple'}, {'fruit': 'orange'}, {'vehicle': 'car'}, {'vehicle': 'bike'}]

Но что мне нужно:

res=>{'fruit': ['apple','orange'], 'vehicle': ['car','bike']}

Как этого добиться? заранее спасибо

ОБНОВЛЕНИЕ Это будет более читабельно. Но вместо этого я хочу один лайнер!

u={}
for i in d1:
    if u.get(i['type']):
        u[i['type']].append(i['name'])
    else:
        u[i['type']]=[i['name']]

Ответы [ 3 ]

3 голосов
/ 10 июля 2020

Что касается однострочника, это должно быть что-то вроде этого:

from itertools import groupby
from operator import itemgetter

res = {k: list(map(itemgetter('name'), v)) for k, v in groupby(sorted(d1, key=itemgetter('type')), itemgetter('type'))}

Что, на мой взгляд, довольно сложно, но вот ...

1 голос
/ 10 июля 2020

Вы можете попробовать этот однострочник:

d1=[{'type':'vehicle','name':'car'},{'type':'fruit','name':'apple'},{'type':'fruit','name':'orange'},{'type':'vehicle','name':'bike'}]

res = {
    k: [d.get('name') for d in d1 if k in d.values()]
    for k in set(list(map(lambda x: x['type'],d1)))
}

print(res)

Или, может быть, вы можете попробовать этот «двухстрочный»:

d1=[{'type':'fruit','name':'apple'},{'type':'fruit','name':'orange'},{'type':'vehicle','name':'car'},{'type':'vehicle','name':'bike'}]

temp=[{d['type']:d['name']} for d in d1]
res = {k: list(filter(None,[d.get(k) for d in temp]))
    for k in set().union(*temp)
}
print(res)

Второе решение основано на ответе Алекса Холла .

Выходы:

{'vehicle': ['car', 'bike'], 'fruit': ['apple', 'orange']}
1 голос
/ 10 июля 2020

Я бы предпочел не использовать здесь одинарный лайнер. Что-то вроде этого, может быть

x = {}
for item in d1:
    x.setdefault(item['type'], []).append(item['name'])

Как по мне, это немного читабельнее

Если вы действительно настаиваете на одинарной подводке, вы можете сделать что-то вроде этого. Но это приведет к созданию пустого списка, такого как [None, None], который будет отброшен

x = {}
[x.setdefault(item['type'], []).append(item['name']) for item in d1]
...