I am using for loop in python and every loop creates a dictionary. I have the below set of dictionaries created.
{'name': 'xxxx'}
{'name': 'yyyy','age':'28'}
{'name': 'zzzz','age':'27','sex':'F'}
My requirement is to compare all the dictionaries created and find out the missing key values and add the key to missing dictionaries and order every dictionary based on key. Below is the expected output
Expected output:
{'age':'','name': 'xxxx','sex':''}
{'age':'28','name': 'yyyy','sex':''}
{'age':'27','name': 'zzzz','sex':'F'}
How to achieve this in python.
If you want to modify the dicts in-place, dict.setdefault would be easy enough.
my_dicts = [
{'name': 'xxxx'},
{'name': 'yyyy','age':'28'},
{'name': 'zzzz','age':'27','sex':'F'},
]
desired_keys = ['name', 'age', 'sex']
for d in my_dicts:
for key in desired_keys:
d.setdefault(key, "")
print(my_dicts)
prints out
[
{'name': 'xxxx', 'age': '', 'sex': ''},
{'name': 'yyyy', 'age': '28', 'sex': ''},
{'name': 'zzzz', 'age': '27', 'sex': 'F'},
]
If you don't want to hard-code the desired_keys list, you can make it a set and gather it from the dicts before the loop above.
desired_keys = set()
for d in my_dicts:
desired_keys.update(set(d)) # update with keys from `d`
Another option, if you want new dicts instead of modifying them in place, is
desired_keys = ... # whichever method you like
empty_dict = dict.fromkeys(desired_keys, "")
new_dicts = [{**empty_dict, **d} for d in my_dicts]
EDIT based on comments:
This doesn't remove keys that are not there in desired keys.
This will leave only the desired keys:
desired_keys = ... # Must be a set
for d in my_dicts:
for key in desired_keys:
d.setdefault(key, "")
for key in set(d) - desired_keys:
d.pop(key)
However, at that point it might be easier to just create new dicts:
new_dicts = [
{key: d.get(value, "") for key in desired_keys}
for d in my_dicts
]
data = [{'name': 'xxxx'},
{'name': 'yyyy','age':'28'},
{'name': 'zzzz','age':'27','sex':'F'}]
First get the maximum, to get all the keys.
Then use dict.get to get default value as empty string for each of the keys, and sort the dictionary on key, you can combine List-comprehension and dict-comprehension:
allKD = max(data, key=len)
[dict(sorted({k:d.get(k, '') for k in allKD}.items(), key=lambda x:x[0])) for d in data]
OUTPUT:
[{'age': '', 'name': 'xxxx', 'sex': ''},
{'age': '28', 'name': 'yyyy', 'sex': ''},
{'age': '27', 'name': 'zzzz', 'sex': 'F'}]
One approach:
from operator import or_
from functools import reduce
lst = [{'name': 'xxxx'},
{'name': 'yyyy', 'age': '28'},
{'name': 'zzzz', 'age': '27', 'sex': 'F'}]
# find all the keys
keys = reduce(or_, map(dict.keys, lst))
# update each dictionary with the complement of the keys
for d in lst:
d.update(dict.fromkeys(keys - d.keys(), ""))
print(lst)
Output
[{'name': 'xxxx', 'age': '', 'sex': ''}, {'name': 'yyyy', 'age': '28', 'sex': ''}, {'name': 'zzzz', 'age': '27', 'sex': 'F'}]
Related
I need to sort list of dictionaries according to predefined list of values
I am using this part of code, and it will work fine but l_of_dicts has values which are not in a sort_l(predefined list of values)
l_of_dicts = [{'name':'Max','years':18},{'name':'John','years':25},{'name':'Ana','years':19},{'name':'Melis','years':38},{'name':'Ivana','years':38}]
sort_l = ['Ana','Melis','John','Max','Peter']
res = sorted(l_of_dicts , key = lambda ele: sort_l .index(list(ele.values())[0]))
I get an error :
ValueError: 'Ivana' is not in list
Is it posible to ignore that values? or even better extract them to another list?
The script bellow does the job but looks heavier than it should be. Maybe there's easier way to do it.
Script:
def sort_dict_list(dict_list, sorting_list):
result = []
not_used_values = []
temp = {}
for index, dictionary in enumerate(dict_list):
temp[dictionary['name']] = index
for item in sorting_list:
if item in temp.keys():
result.append(dict_list[temp[item]])
else:
not_used_values.append(item)
return result, not_used_values
You could do some preprocessing to store the ordering of only names in l_of_dicts:
l_of_dicts = [{'name': 'Max', 'years': 18}, {'name': 'John', 'years': 25},
{'name': 'Ana', 'years': 19}, {'name': 'Melis', 'years': 38}]
names_in_dicts = {d['name'] for d in l_of_dicts if 'name' in d}
sort_l = ['Ana', 'Melis', 'Ivana', 'John', 'Max', 'Peter']
sort_order = {name: order for order, name in enumerate(sort_l) if name in
names_in_dicts}
print(sort_order) # {'Ana': 0, 'Melis': 1, 'John': 3, 'Max': 4}
sorted_l_of_dicts = sorted(l_of_dicts, key=lambda d: sort_order[d['name']])
print(sorted_l_of_dicts) # [{'name': 'Ana', 'years': 19}, {'name': 'Melis', 'years': 38}, {'name': 'John', 'years': 25}, {'name': 'Max', 'years': 18}]
I want to take two lists with dict value and find the specific values that appear only in first list.
In this case, only compare 'name' key.
a = [
{'name': 'joseph', 'age': 33},
{'name': 'Emma', 'age': 11},
{'name': 'apple', 'age': 44}
]
b = [
{'name': 'apple', 'age': 44},
{'name': 'Emma', 'age': 22}
]
returnOnlyOne(a, b)
would return [{'name': 'joseph', 'age': 33}], for instance.
The set() solution is not for this case.
For efficiency, we first make a set of the names in b, then filter the list a:
from operator import itemgetter
def returnOnlyOne(a, b):
b_names = set(map(itemgetter('name'), b))
only_in_a = list(filter(lambda item: item['name'] not in b_names, a))
return only_in_a
Sample output:
a = [
{'name': 'joseph', 'age': 33},
{'name': 'Emma', 'age': 11},
{'name': 'apple', 'age': 44}
]
b = [
{'name': 'apple', 'age': 44},
{'name': 'Emma', 'age': 22}
]
print(returnOnlyOne(a, b))
# [{'name': 'joseph', 'age': 33}]
If you don't like itemgetter, filter and the like, you can write the same using comprehensions:
def returnOnlyOne(a, b):
b_names = set(item['name'] for item in b)
return [ item for item in a if item['name'] not in b_names]
Use list comprehension with map. (BTW, what's inside your list is called dict):
[d for d in a if d.get('name') not in list(map(lambda x:x.get('name'), b))]
# [{'age': 33, 'name': 'joseph'}]
Explanation:
list(map(lambda x:x.get('name'), b)): gets all name from b
d.get('name') not in: checks if name from a doesn't exist in b. (i.e. appear only in first list)
Nearly the same as the others.
print([ item for item in a if item['name'] not in set(item['name'] for item in b)])
I have a list with this format
l = ['Rick', 25, 'Student', 'rick#mail.com']
and I need a dict with this format
{'Name': 'Rick', 'Age': 25, 'E-mail': 'rick#mail.com', 'Position': 'Student'}
In my head the solution is iterate over the list and put each value inside the key dict. Are there other (Simplified) solution?
keys = ['name', 'age', 'job', 'email']
values = ['Rick', 25, 'Student', 'rick#mail.com']
key_dict = dict(zip(keys, values))
print(key_dict)
# {'name': 'Rick', 'age': 25, 'job': 'Student', 'email': 'rick#mail.com'}
Use zip() to join the keys and the values in l together, and then convert to a dictionary with dict as seen here:
>>> dict(zip(('Name', 'Age', 'Role', 'E-mail'), l))
{'Name': 'Rick', 'E-mail': 'rick#mail.com', 'Role': 'Student', 'Age': 25}
Or, if you wanted to omit the 'Student' element all together, you could just slice at the third index:
>>> dict(zip(('Name', 'Age', 'E-mail'), l[:2] + l[3:]))
{'Name': 'Rick', 'E-mail': 'rick#mail.com', 'Age': 25}
Or use a generator:
>>> dict(zip(('Name', 'Age', 'E-mail'), (a for a in l if a is not 'Student')))
{'Name': 'Rick', 'E-mail': 'rick#mail.com', 'Age': 25}
You should use zip(). It will merge to lists into an immutable dict.
keys = ['name', 'age', 'position', 'email']
values = ['Rick', 25, 'Student', 'rick#mail.com']
zippeddict = dict(zip(keys, values))
For some reason my small small brain is having problems with this, I have a list of tuples list = [('name:john','age:25','location:brazil'),('name:terry','age:32','location:acme')]. Im trying to move these values into a dictionary for parsing later. I have made a few attempts, below the latest of these and im not getting all results into the dict, the dict ends up with the last value iterated (its recreating the dict each time).
people = {}
list = [('name:john','age:25','location:brazil'),('name:terry','age:32','location:acme')]
for value in list:
people = {'person': [dict(item.split(":",1) for item in value)]}
You can try this one too:
inlist = [('name:john','age:25','location:brazil'),('name:terry','age:32','location:acme')]
d = []
for tup in inlist:
tempDict = {}
for elem in tup:
elem = elem.split(":")
tempDict.update({elem[0]:elem[1]})
d.append({'person':tempDict})
print(d)
Output:
[{'person': {'location': 'brazil', 'name': 'john', 'age': '25'}}, {'person': {'location': 'acme', 'name': 'terry', 'age': '32'}}]
If you want a dictionary with a key person and values the dictionaries with the people's info, then replace d.append({'person':tempDict}) with d.append(tempDict) and add d = {'person':d} right before printing.
Output:
{'person': [{'location': 'brazil', 'name': 'john', 'age': '25'}, {'location': 'acme', 'name': 'terry', 'age': '32'}]}
You can try this:
l = [('name:john','age:25','location:brazil'),('person:terry','age:32','location:acme')]
people = [{c:d for c, d in [i.split(':') for i in a]} for a in l]
Output:
[{'name': 'john', 'age': '25', 'location': 'brazil'}, {'person': 'terry', 'age': '32', 'location': 'acme'}]
First of all try not to call your list list. This name is protected in python and used usually to get a list out of iterators or ranges etc.
I would make a list of people first and then append each person to the people list as separate dictionary as follows:
people = []
my_list = [('name:john','age:25','location:brazil'),('person:terry','age:32','location:acme')]
for tup in my_list:
person = {}
for item in tup:
splitted = item.split(':')
person.update({splitted[0]:splitted[1]})
people.append(person)
The output then would be this:
[{'age': '25', 'location': 'brazil', 'name': 'john'},
{'age': '32', 'location': 'acme', 'person': 'terry'}]
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