I have been given the following list of dictionaries:
names = [
{'first_name': 'Jane', 'last_name': 'Doe'},
{'first_name': 'John', 'last_name': 'Kennedy'},
{'first_name': 'Ada', 'last_name': 'Lovelace'}
]
Part a was to return an array of full names, which I did as follows:
[user['first_name'] +' '+ user['last_name'] for user in names]
It returned the following:
['Jane Doe', 'John Kennedy', 'Ada Lovelace']
Part b is to Now do the same thing above, only return a list of dictionaries, with 'name' being the key. Result should be:
python
[{'name':'Jane Doe'},{'name':'John Kennedy'},{'name': 'Ada Lovelace'}]
I have tried everything I can think of. From trying to change the key, to changing back to a list and then back to a dictionary. I'm very new at Python and would appreciate any help possible.
[{'name': '{first_name} {last_name}'.format(**n)} for n in names]
The following comprehension using join will work:
result = [{'name': ' '.join((d['first_name'], d['last_name']))} for d in names]
# [{'name': 'Jane Doe'}, {'name': 'John Kennedy'}, {'name': 'Ada Lovelace'}]
Adjust your list comprehension to the following:
names = [
{'first_name': 'Jane', 'last_name': 'Doe'},
{'first_name': 'John', 'last_name': 'Kennedy'},
{'first_name': 'Ada', 'last_name': 'Lovelace'}
]
result = [{'name':d['first_name']+' '+ d['last_name']} for d in names]
print(result)
The output:
[{'name': 'Jane Doe'}, {'name': 'John Kennedy'}, {'name': 'Ada Lovelace'}]
list(map(lambda d: {'name': ' '.join((d['first_name'], d['last_name']))},names))
Related
Example list of dicts:
[{'name': 'aly', 'age': '104'}, {'name': 'Not A name', 'age': '99'}]
Expected out = ['aly', '104', 'Not A name', '99']
Any help will be much appreciated.
Thanks!
Try this in one line:
d = [{'name': 'aly', 'age': '104'}, {'name': 'Not A name', 'age': '99'}]
[v for i in d for k,v in i.items()]
The result will be:
Out[1]: ['aly', '104', 'Not A name', '99']
Another way :
listDictionary = [{'name': 'aly', 'age': '104'}, {'name': 'Not A name', 'age': '99'}]
out = []
for i in listDictionary:
for k, v in i.items():
out.append(v)
print(out)
Output : ['aly', '104', 'Not A name', '99']
I am getting along with dict comprehensions and trying to understand how the below 2 dict comprehensions work:
select_vals = ['name', 'pay']
test_dict = {'data': [{'name': 'John', 'city': 'NYC', 'pay': 70000}, {'name': 'Mike', 'city': 'NYC', 'pay': 80000}, {'name': 'Kate', 'city': 'Houston', 'pay': 65000}]}
dict_comp1 = [{key: item[key] for key in select_vals } for item in test_dict['data'] if item['pay'] > 65000 ]
The above line gets me
[{'name': 'John', 'pay': 70000}, {'name': 'Mike', 'pay': 80000}]
dict_comp2 = [{key: item[key]} for key in select_vals for item in test_dict['data'] if item['pay'] > 65000 ]
The above line gets me
[{'name': 'John'}, {'name': 'Mike'}, {'pay': 70000}, {'pay': 80000}]
How does the two o/ps vary when written in a for loop ? When I execute in a for loop
dict_comp3 = []
for key in select_vals:
for item in test_dict['data']:
if item['pay'] > 65000:
dict_comp3.append({key: item[key]})
print(dict_comp3)
The above line gets me same as dict_comp2
[{'name': 'John'}, {'name': 'Mike'}, {'pay': 70000}, {'pay': 80000}]
How do I get the o/p as dict_comp1 in a for loop ?
The select vals iteration should be the inner one
result = []
for item in test_dict['data']:
if item['pay'] > 65000:
aux = {}
for key in select_vals:
aux[key] = item[key]
result.append(aux)
Is there a built-in function that works like zip(), but fills the results so that the length of the resulting list is the length of the longest input and fills the list from the left with e.g. None?
There is already an answer using zip_longest from itertools module and the corresponding question is very similar to this. But with zip_longest it seems that you can only fill missing data from the right.
Here might be a use case for that, assuming we have names stored only like this (it's just an example):
header = ["title", "firstname", "lastname"]
person_1 = ["Dr.", "Joe", "Doe"]
person_2 = ["Mary", "Poppins"]
person_3 = ["Smith"]
There is no other permutation like (["Poppins", "Mary"], ["Poppins", "Dr", "Mary"]) and so on.
How can I get results like this using built-in functions?
>>> dict(magic_zip(header, person_1))
{'title': 'Dr.', 'lastname': 'Doe', 'firstname': 'Joe'}
>>> dict(magic_zip(header, person_2))
{'title': None, 'lastname': 'Poppins', 'firstname': 'Mary'}
>>> dict(magic_zip(header, person_3))
{'title': None, 'lastname': 'Smith', 'firstname': None}
Use zip_longest but reverse lists.
Example:
from itertools import zip_longest
header = ["title", "firstname", "lastname"]
person_1 = ["Dr.", "Joe", "Doe"]
person_2 = ["Mary", "Poppins"]
person_3 = ["Smith"]
print(dict(zip_longest(reversed(header), reversed(person_2))))
# {'lastname': 'Poppins', 'firstname': 'Mary', 'title': None}
On your use cases:
>>> dict(zip_longest(reversed(header), reversed(person_1)))
{'title': 'Dr.', 'lastname': 'Doe', 'firstname': 'Joe'}
>>> dict(zip_longest(reversed(header), reversed(person_2)))
{'lastname': 'Poppins', 'firstname': 'Mary', 'title': None}
>>> dict(zip_longest(reversed(header), reversed(person_3)))
{'lastname': 'Smith', 'firstname': None, 'title': None}
Simply use zip_longest and read the arguments in the reverse direction:
In [20]: dict(zip_longest(header[::-1], person_1[::-1]))
Out[20]: {'lastname': 'Doe', 'firstname': 'Joe', 'title': 'Dr.'}
In [21]: dict(zip_longest(header[::-1], person_2[::-1]))
Out[21]: {'lastname': 'Poppins', 'firstname': 'Mary', 'title': None}
In [22]: dict(zip_longest(header[::-1], person_3[::-1]))
Out[22]: {'lastname': 'Smith', 'firstname': None, 'title': None}
Since the zip* functions need to be able to work on general iterables, they don't support filling "from the left", because you'd need to exhaust the iterable first. Here we can just flip things ourselves.
The generic "magic zip" generator function with a variable number of args (which only uses lazy-evaluation functions and no python loops):
import itertools
def magic_zip(*args):
return itertools.zip_longest(*map(reversed,args))
testing (of course in the case of a dict build, only 2 params are needed):
for p in (person_1,person_2,person_3):
print(dict(magic_zip(header,p)))
result:
{'lastname': 'Doe', 'title': 'Dr.', 'firstname': 'Joe'}
{'lastname': 'Poppins', 'title': None, 'firstname': 'Mary'}
{'lastname': 'Smith', 'title': None, 'firstname': None}
def magic_zip(*lists):
max_len = max(map(len, lists))
return zip(*([None] * (max_len - len(l)) + l for l in lists))
Pulling my hair out with this one.
I have a list of dictionaries without a unique primary ID key for each unique entry (the dictionary is built on the fly):
dicts = [{'firstname': 'john', 'lastname': 'doe', 'code': 'crumpets'},
{'firstname': 'john', 'lastname': 'roe', 'code': 'roe'},
{'firstname': 'john', 'lastname': 'doe', 'code': 'crumpets'},
{'firstname': 'thom', 'lastname': 'doe', 'code': 'crumpets'},
]
How do I go about filtering out lists of dictionaries like this where any repeating {} within the list are removed? So I need to check if all three of the dictionary keys match up with another in the list...and then discard that from the dict if that check is met.
So, for my example above, the first and third "entries" need to be removed as they are duplicates.
You use create frozensets from the dicts and put those in a set to remove dupes:
dcts = [dict(d) for d in set(frozenset(d.items()) for d in dcts)]
print(dcts)
[{'code': 'roe', 'firstname': 'john', 'lastname': 'roe'},
{'code': 'crumpets', 'firstname': 'thom', 'lastname': 'doe'},
{'code': 'crumpets', 'firstname': 'john', 'lastname': 'doe'}]
If you choose to remove all entries of the duplicates you can use a counter:
from collections import Counter
dcts = [dict(d) for d, cnt in Counter(frozenset(d.items()) for d in dcts).items()
if cnt==1]
print(dcts)
[{'code': 'roe', 'firstname': 'john', 'lastname': 'roe'},
{'code': 'crumpets', 'firstname': 'thom', 'lastname': 'doe'}]
Remove duplicates in a list of non-hashable elements requires you to make them hashable on the fly:
def remove_duplicated_dicts(elements):
seen = set()
result = []
for element in elements:
element_as_tuple = tuple(element.items())
if element_as_tuple not in seen:
seen.add(element_as_tuple)
result.append(element)
return result
d = [{'firstname': 'john', 'lastname': 'doe', 'code': "crumpets"},
{'firstname': 'john', 'lastname': 'roe', 'code': "roe"},
{'firstname': 'john', 'lastname': 'doe', 'code': "crumpets"},
{'firstname': 'thom', 'lastname': 'doe', 'code': "crumpets"},
]
print(remove_duplicated_dicts(d))
PS.
Non-obvious differences with the accepted answer of Moses Koledoye (as of 2017-06-19 at 13:00:00):
preservation of the original list order;
faster conversions: dict -> tuple instead of dict -> frozendict -> dict (take it with a grain of salt: I have made no benchmark).
Given the values of the dictionary are hashable, we can generate our own uniqness filter:
def uniq(iterable, key = lambda x:x):
keys = set()
for item in iterable:
ky = key(item)
if ky not in keys:
yield item
keys.add(ky)
We can then simply use the filter, like:
list(uniq(dicts,key=lambda x:(x['firstname'],x['lastname'],x['code'])))
The filter maintains the original order, and will - for this example - generate:
>>> list(uniq(dicts,key=lambda x:(x['firstname'],x['lastname'],x['code'])))
[{'code': 'crumpets', 'firstname': 'john', 'lastname': 'doe'},
{'code': 'roe', 'firstname': 'john', 'lastname': 'roe'},
{'code': 'crumpets', 'firstname': 'thom', 'lastname': 'doe'}]
I have a list of dict what some data, and I would like to extract certain key:value pairs into a new list of dicts. I know one way that I could do this would be to use del i['unwantedKey'], however, I would rather not delete any data but instead create a new dict with the needed data.
The column order might change, so I need something to extract the two key:value pairs from the larger dict into a new dict.
Current Data Format
[{'Speciality': 'Math', 'Name': 'Matt', 'Location': 'Miami'},
{'Speciality': 'Science', 'Name': 'Ben', 'Location': 'Las Vegas'},
{'Speciality': 'Language Arts', 'Name': 'Sarah', 'Location': 'Washington DC'},
{'Speciality': 'Spanish', 'Name': 'Tom', 'Location': 'Denver'},
{'Speciality': 'Chemistry', 'Name': 'Jim', 'Location': 'Dallas'}]
Code to delete key:value from dict
import csv
data= []
for line in csv.DictReader(open('data.csv')):
data.append(line)
for i in data:
del i['Speciality']
print data
Desired Data Format without using del i['Speciality']
[{'Name': 'Matt', 'Location': 'Miami'},
{'Name': 'Ben', 'Location': 'Las Vegas'},
{'Name': 'Sarah', 'Location': 'Washington DC'},
{'Name': 'Tom', 'Location': 'Denver'},
{'Name': 'Jim', 'Location': 'Dallas'}]
If you want to give a positive list of keys to copy over into the new dictionaries:
import csv
with open('data.csv', 'rb') as csv_file:
data = list(csv.DictReader(csv_file))
keys = ['Name', 'Location']
new_data = [dict((k, d[k]) for k in keys) for d in data]
print new_data
suppose we have,
l1 = [{'Location': 'Miami', 'Name': 'Matt', 'Speciality': 'Math'},
{'Location': 'Las Vegas', 'Name': 'Ben', 'Speciality': 'Science'},
{'Location': 'Washington DC', 'Name': 'Sarah', 'Speciality': 'Language Arts'},
{'Location': 'Denver', 'Name': 'Tom', 'Speciality': 'Spanish'},
{'Location': 'Dallas', 'Name': 'Jim', 'Speciality': 'Chemistry'}]
to create a new list of dictionaries that do not contain the keys 'Speciality' we can do,
l2 = []
for oldd in l1:
newd = {}
for k,v in oldd.items():
if k != 'Speciality':
newd[k] = v
l2.append(newd)
and now l2 will be your desired output. In general you can exclude an arbitrary list of keys like so
exclude_keys = ['Speciality', 'Name']
l2 = []
for oldd in l1:
newd = {}
for k,v in oldd.items():
if k not in exclude_keys:
newd[k] = v
l2.append(newd)
the same can be done with an include_keys variable
include_keys = ['Name', 'Location']
l2 = []
for oldd in l1:
newd = {}
for k,v in oldd.items():
if k in include_keys:
newd[k] = v
l2.append(newd)
You can create a new list of dicts limited to the keys you want with one line of code (Python 2.6+):
NLoD=[{k:d[k] for k in ('Name', 'Location')} for d in LoD]
Try it:
>>> LoD=[{'Speciality': 'Math', 'Name': 'Matt', 'Location': 'Miami'},
{'Speciality': 'Science', 'Name': 'Ben', 'Location': 'Las Vegas'},
{'Speciality': 'Language Arts', 'Name': 'Sarah', 'Location': 'Washington DC'},
{'Speciality': 'Spanish', 'Name': 'Tom', 'Location': 'Denver'},
{'Speciality': 'Chemistry', 'Name': 'Jim', 'Location': 'Dallas'}]
>>> [{k:d[k] for k in ('Name', 'Location')} for d in LoD]
[{'Name': 'Matt', 'Location': 'Miami'}, {'Name': 'Ben', 'Location': 'Las Vegas'}, {'Name': 'Sarah', 'Location': 'Washington DC'}, {'Name': 'Tom', 'Location': 'Denver'}, {'Name': 'Jim', 'Location': 'Dallas'}]
Since you are using csv, you can limit the columns that you read in the first place to the desired columns so you do not need to delete the undesired data:
dc=('Name', 'Location')
with open(fn) as f:
reader=csv.DictReader(f)
LoD=[{k:row[k] for k in dc} for row in reader]
keys_lst = ['Name', 'Location']
new_data={key:val for key,val in event.items() if key in keys_lst}
print(new_data)