keys = ['id', 'name', 'address']
list = [{'Value': 1}, {'Value': 'Example name'}, {'VarCharValue': 'GA'}]
Looking for the most pythonic way to replace key dicts keys. I tried with for loop and list indexes but it was ugly. Excepted result:
list = [{'id': 1}, {'name': 'Example name'}, {'address': 'GA'}]
You can use a list comprehension with zip. To extract the only value in a dictionary d, you can use next(iter(d.values())) or list(d.values())[0].
K = ['id', 'name', 'address']
L = [{'Value': 1}, {'Value': 'Example name'}, {'VarCharValue': 'GA'}]
res = [{k: next(iter(v.values()))} for k, v in zip(K, L)]
[{'id': 1}, {'name': 'Example name'}, {'address': 'GA'}]
If you don't want to use iter(), you can use list(), which looks almost the same as jpp's solution
res = [{k: list(v.values())[0]} for k,v in zip(K,L)]
In this, you simply convert the dict_values object to a list, and get the first item, instead of getting the iterator and calling next on it.
Related
Fairly new to list comprehension and have the_list that I want to extract the keys of nested dictionary but I got the values instead. What am I missing or what am I doing wrong?
the_list = [{'size': 0, 'values': [], 'start': 0}, {'size': 2, 'values': [{'user': {'name': 'anna', 'id': 10, 'displayName': 'Anna'}, 'category': 'Secretary'}, {'user': {'name': 'bob', 'id': 11, 'displayName': 'Bobby'}, 'category': 'Manager'}], 'start': 0}, {'size': 1, 'values': [{'user': {'name': 'claire', 'id': 13, 'displayName': 'Clarissa Claire'}, 'category': 'Secretary'}], 'start': 0}]
list_comprehension = []
list_comprehension = [x for x in the_list for x in the_list[1]['values'][0]]
print(list_comprehension)
>> ['user', 'category', 'user', 'category', 'user', 'category']
Want
list_comprehension = [[anna, Secretary], [bob, manager], [claire, Secretary]]
You could use this. I personnally try to avoid nested list comprehension as they are hard to read and debug.
[[x['category'], x['user']['displayName']] for nest_list in the_list for x in nest_list["values"] ]
Output:
[['Secretary', 'Anna'], ['Manager', 'Bobby'], ['Secretary', 'Clarissa Claire']]
EDIT:
A version that doesn't have a nested comprehension list. When doing it I realised that there was one more level than I realised that makes this version a bit long. So in the end I'm not sure which one I would use in prod.
result = []
dict_list = [nest_list["values"] for nest_list in the_list]
for elt in dict_list:
for d in elt:
result.append([d['category'], d['user']['displayName']])
I've come up with this solution, but it is not very readable ...
comprehensionList = [[user['user']['name'], user['category']] for x in the_list for user in x['values']]
# Output
[['anna', 'Secretary'], ['bob', 'Manager'], ['claire', 'Secretary']]
I have a dictionary of lists of dictionaries that looks like this:
original_dict = {
1: [{'name': 'Sam'}, {'name': 'Mahmoud'}, {'name': 'Xiao'}],
2: [{'name': 'Olufemi'}, {'name': 'Kim'}, {'name': 'Rafael'}]
}
I know that the names in the lists in this dictionary are all unique. IE: the same name will not appear multiple times in this structure. I want to compile a dictionary of all sub-dictionaries, keyed by their names. I want the result to look like this:
result_dict = {
'Sam': {'name': 'Sam'},
'Mahmoud': {'name': 'Mahmoud'},
'Xiao': {'name': 'Xiao'},
'Olufemi': {'name': 'Olufemi'},
'Kim': {'name': 'Kim'},
'Rafael': {'name': 'Rafael'}
}
So far my solution looks like this:
result_dict = {}
for list_of_dicts in original_dict.values:
for curr_dict in list_of_dicts:
result_dict[curr_dict['name']] = curr_dict
But is there a more pythonic/compact way to do this? Maybe using dict comprehension?
You can use dictionary comprehension.
result = {name['name']: name for k, v in original.items() for name in v}
The inner for loop will iterate through all the key value pairs and the outer will iterate through each name in each value.
Yes, just rewrite your loops as a dict comprehension:
original = {
1: [{'name': 'Sam'}, {'name': 'Mahmoud'}, {'name': 'Xiao'}],
2: [{'name': 'Olufemi'}, {'name': 'Kim'}, {'name': 'Rafael'}]
}
result = {d['name']: d for l in original.values() for d in l}
from pprint import pprint
pprint(result)
Output:
{'Kim': {'name': 'Kim'},
'Mahmoud': {'name': 'Mahmoud'},
'Olufemi': {'name': 'Olufemi'},
'Rafael': {'name': 'Rafael'},
'Sam': {'name': 'Sam'},
'Xiao': {'name': 'Xiao'}}
I have a list of dictionary:
[{'name':'Jay', 'value':'1'},{'name':'roc', 'value':'9'},{'name':'Jay', 'value':'7'},{'name':'roc', 'value':'2'}]
I want it to be:
[{'name':'Jay', 'value':'8'},{'name':'roc', 'value':'11'}]
I tried looping through but I am not able to find an example where I can do this. Any hint or idea will be appreciated.
You can use a defaultdict:
lst = [{'name':'Jay', 'value':'1'},{'name':'roc', 'value':'9'},{'name':'Jay', 'value':'7'},{'name':'roc', 'value':'2'}]
1) sum values for each name:
from collections import defaultdict
result = defaultdict(int)
for d in lst:
result[d['name']] += int(d['value'])
2) convert the name-value pair to a dictionary within a list:
[{'name': name, 'value': value} for name, value in result.items()]
# [{'name': 'roc', 'value': 11}, {'name': 'Jay', 'value': 8}]
Or if you want the value as str type as commented by #Kevin:
[{'name': name, 'value': str(value)} for name, value in result.items()]
# [{'name': 'roc', 'value': '11'}, {'name': 'Jay', 'value': '8'}]
This is a good use case for itertools.groupby.
from itertools import groupby
from operator import itemgetter
orig = [{'name':'Jay', 'value':'1'},
{'name':'roc', 'value':'9'},
{'name':'Jay', 'value':'7'},
{'name':'roc', 'value':'2'}]
get_name = itemgetter('name')
result = [{'name': name, 'value': str(sum(int(d['value']) for d in dicts))}
for name, dicts in groupby(sorted(orig, key=get_name), key=get_name)]
Breaking it down:
get_name is a function that given a dictionary, returns the value of its "name" key. I.e., get_name = lambda x: x['name'].
sorted returns the list of dictionaries sorted by the value of the "name" key.
groupby returns an iterator of (name, dicts) where dicts is a list (ok, generator) of the dicts that share name as the value of the "name" key. (Grouping only occurs for consecutive items with the same key value, hence the need to sort the list in the previous step.)
The result is a list of new dictionaries using the given name and the sum of all the related "value" elements.
Similar to Psidom's answer but using collections.Counter which is the perfect candidate for accumulating integer values.
import collections
d =[{'name':'Jay', 'value':'1'},{'name':'roc', 'value':'9'},{'name':'Jay', 'value':'7'},{'name':'roc', 'value':'2'}]
c = collections.Counter()
for sd in d:
c[sd["name"]] += int(sd["value"])
Then, you need to rebuild the dicts if needed, by converting back to string.
print([{"name":n,"value":str(v)} for n,v in c.items()])
result:
[{'name': 'Jay', 'value': '8'}, {'name': 'roc', 'value': '11'}]
For the sake of completeness, without collections.defaultdict:
data = [{'name': 'Jay', 'value': '1'}, {'name': 'roc', 'value': '9'},
{'name': 'Jay', 'value': '7'}, {'name': 'roc', 'value': '2'}]
result = {}
# concetrate
for element in data:
result[element["name"]] = result.get(element["name"], 0) + int(element["value"])
# unpack
result = [{"name": element, "value": result[element]} for element in result]
# optionally, you can loop through result.items()
# you can, also, turn back result[elements] to str if needed
print(result)
# prints: [{'name': 'Jay', 'value': 8}, {'name': 'roc', 'value': 11}]
Another way to solve your question by using groupby from itertools module:
from itertools import groupby
a = [{'name':'Jay', 'value':'1'},{'name':'roc', 'value':'9'},{'name':'Jay', 'value':'7'},{'name':'roc', 'value':'2'}]
final = []
for k,v in groupby(sorted(a, key= lambda x: x["name"]), lambda x: x["name"]):
final.append({"name": k, "value": str(sum(int(j["value"]) for j in list(v)))})
print(final)
Output:
[{'name': 'Jay', 'value': '8'}, {'name': 'roc', 'value': '11'}]
ld = [{'name':'Jay', 'value':'1'},{'name':'roc', 'value':'9'},{'name':'Jay', 'value':'7'},{'name':'roc', 'value':'2'}]
tempDict = {}
finalList = []
for d in ld:
name = d['name']
value = d['value']
if name not in tempDict:
tempDict[name] = 0
tempDict[name] += int(value)
#tempDict => {'Jay': 8, 'roc': 11}
for name,value in tempDict.items():
finalList.append({'name':name,'value':value})
print(finalList)
# [{'name': 'Jay', 'value': 8}, {'name': 'roc', 'value': 11}]
Here's another way using pandas
names = [{'name':'Jay', 'value':'1'},{'name':'roc', 'value':'9'},{'name':'Jay', 'value':'7'},
{'name':'roc', 'value':'2'}]
df = pd.DataFrame(names)
df['value'] = df['value'].astype(int)
group = df.groupby('name')['value'].sum().to_dict()
result = [{'name': name, 'value': value} for name, value in group.items()]
Which outputs:
[{'value': 8, 'name': 'Jay'}, {'value': 11, 'name': 'roc'}]
i have a list, i want get key=value in other list
for example:
my_list = [
{'Key': 'Apple', 'Value': 'Fruit'},
{'Key': 'Car', 'Value': 'Automobile'},
{'Key': 'Dog', 'Value': 'Animal'},
{'Key': 'Bolt', 'Value': 'Runner'}]
I have a my_list, i want to get output as:
new_list = ['Apple=Fruit', 'Car=Automobile', 'Dog=Animal', 'Bolt=Runner']
Using a list comprehension with join
>>> my_list=[{'Key':'Apple','Value':'Fruit'},
{'Key':'Car','Value':'Automobile'},
{'Key':'Dog','Value':'Animal'},
{'Key':'Bolt','Value':'Runner'}]
>>> new_list = ['='.join([i['Key'], i['Value']]) for i in my_list]
>>> new_list
['Apple=Fruit', 'Car=Automobile', 'Dog=Animal', 'Bolt=Runner']
I am a bit confused by your naming though. With the names 'Key' and 'Value' are you actually intending to make a dict? As your expected output is written (and my above code produces) it is a list of concatenated strings.
If you do indeed want to make a dict out of these, you can do something similar
my_list=[{'Key':'Apple','Value':'Fruit'},
{'Key':'Car','Value':'Automobile'},
{'Key':'Dog','Value':'Animal'},
{'Key':'Bolt','Value':'Runner'}]
>>> new_dict = {i['Key'] : i['Value'] for i in my_list}
>>> new_dict
{'Car': 'Automobile', 'Bolt': 'Runner', 'Apple': 'Fruit', 'Dog': 'Animal'}
Alternative implementation, using map and str.format:
>>> my_list=[{'Key': 'Apple', 'Value': 'Fruit'},
{'Key': 'Car', 'Value': 'Automobile'},
{'Key': 'Dog', 'Value': 'Animal'},
{'Key': 'Bolt', 'Value': 'Runner'}]
>>> map(lambda d: "{Key}={Value}".format(**d), my_list)
['Apple=Fruit', 'Car=Automobile', 'Dog=Animal', 'Bolt=Runner']
Or (likely to be considerably more use in the long run):
>>> {d['Key']: d['Value'] for d in my_list}
{'Car': 'Automobile', 'Bolt': 'Runner', 'Apple': 'Fruit', 'Dog': 'Animal'}
Using str.format and accessing each dict's values
["{}={}".format(d.values()[1],d.values()[0]) for d in my_list]
['Apple=Fruit', 'Car=Automobile', 'Dog=Animal', 'Bolt=Runner']
Or using the keys:
["{}={}".format(d["Key"],d["Value"]) for d in my_list]
Suppose I have a list like so:
[{'name': 'Blah1', 'age': x}, {'name': 'Blah2', 'age': y}, {'name': None, 'age': None}]
It is guaranteed that both 'name' and 'age' values will either be filled or empty.
I tried this:
for person_dict in list:
if person_dict['name'] == None:
list.remove(person_dict)
But obviously that does not work because the for loop skips over an index sometimes and ignores some blank people.
I am relatively new to Python, and I am wondering if there is a list method that can target dicts with a certain value associated with a key.
EDIT: Fixed tuple notation to list as comments pointed out
Just test for the presence of None in the dict's values to test ALL dict keys for the None value:
>>> ToD=({'name': 'Blah1', 'age': 'x'}, {'name': 'Blah2', 'age': 'y'}, {'name': None, 'age': None})
>>> [e for e in ToD if None not in e.values()]
[{'age': 'x', 'name': 'Blah1'}, {'age': 'y', 'name': 'Blah2'}]
Or, use filter:
>>> filter(lambda d: None not in d.values(), ToD)
({'age': 'x', 'name': 'Blah1'}, {'age': 'y', 'name': 'Blah2'})
Or, if it is a limited test to 'name':
>>> filter(lambda d: d['name'], ToD)
({'age': 'x', 'name': 'Blah1'}, {'age': 'y', 'name': 'Blah2'})
You can use list comprehension as a filter like this
[c_dict for c_dict in dict_lst if all(c_dict[key] is not None for key in c_dict)]
This will make sure that you get only the dictionaries where all the values are not None.
for index,person_dict in enumerate(lis):
if person_dict['name'] == None:
del lis[index]
you can also try
lis=[person_dict for person_dict in lis if person_dict['name'] != None]
never use List as variable
You can create new list with accepted data. If you have tuple then you have to create new list.
List comprehension could be faster but this version is more readable for beginners.
data = ({'name': 'Blah1', 'age': 'x'}, {'name': 'Blah2', 'age': 'y'}, {'name': None, 'age': None})
new_data = []
for x in data:
if x['name']: # if x['name'] is not None and x['name'] != ''
new_data.append(x)
print new_data