Combine Dictionarys in a list based on a value - python

I can't get my head around this problem:
I have a List:
[{'name' : 'Bob', 'Salary2014' : 2000}, {'name': 'Alice', 'Salary2014' : 1000}, {'name':'Bob', 'Salary2013' : 1500}]
I want to join the dictionarys on base of the Name (which is unique)
[{'name' : 'Bob', 'Salary2014' : 2000, 'Salary2013' : 1500}, {'name': 'Alice', 'Salary2014' : 1000}]
I know the solution has to be simple and may involve the .update method, but I just don't get it.

Use a new dictionary to track your dictionaries based on name:
combined = {}
for d in yourlist:
combined.setdefault(d['name'], {}).update(d)
output = combined.values()
The combined.setdefault() method here sets {} as a default value if d['name'] is not present, then updates the dictionary with the current iteration.
If you are using Python 3, use list(combined.values()).
Demo:
>>> yourlist = [{'name' : 'Bob', 'Salary2014' : 2000}, {'name': 'Alice', 'Salary2014' : 1000}, {'name':'Bob', 'Salary2013' : 1500}]
>>> combined = {}
>>> for d in yourlist:
... combined.setdefault(d['name'], {}).update(d)
...
>>> combined.values()
[{'Salary2013': 1500, 'name': 'Bob', 'Salary2014': 2000}, {'name': 'Alice', 'Salary2014': 1000}]

The other pretty similar way is to use defaultdict:
from collections import defaultdict
inp = [{'name': 'Bob', 'Salary2014': 2000},
{'name': 'Alice', 'Salary2014': 1000},
{'name': 'Bob', 'Salary2013': 1500}]
out = defaultdict(dict)
for rec in inp:
out[rec['name']].update(rec)
print out.values()

Related

How to loop through a list of dictionary and extract those with the same 'name' and 'school' into a new list while getting their other values in it

I have this list of dictionary and I would like to get those with the same exact value of 'name' and 'school' into a new list and also getting their 'age' merged into a list as well and the rest of the dictionary that is not identical to just add into the list as per usual..
Here is an example of the list of dictionary
[{'name': 'Jane', 'age':12, 'school': 'SIT'}, {'name': 'John', 'age':13, 'school': 'SMU'},{'name': 'Jane', 'age':14, 'school': 'SIT'}, {'name': 'Jane', 'age':16, 'school': 'SIT'}, {'name': 'John', 'age':13, 'school': 'NUS'}]
and I would like it to make it into something like this..
[{'name': 'Jane', 'age': [12,14,16], 'school': 'SIT'}, {'name': 'John', 'age': 13, 'school': 'SMU'}, {'name': 'John', 'age':13, 'school': 'NUS'}]
using Python.. please help!
tried using counter, loops but still can't get it to work..
You could use itertools.groupby().
Example:
import itertools
from pprint import pprint
data = [{'name': 'Jane', 'age':12, 'school': 'SIT'}, {'name': 'John', 'age':13, 'school': 'SMU'},{'name': 'Jane', 'age':14, 'school': 'SIT'}, {'name': 'Jane', 'age':16, 'school': 'SIT'}, {'name': 'John', 'age':13, 'school': 'NUS'}]
keyfunc = lambda x: (x["name"], x["school"])
# needs to be sorted to use groupby
data.sort(key=keyfunc)
output = []
for k,v in itertools.groupby(data, key=keyfunc):
this_group = {
"name": k[0],
"school": k[1],
"age": [i["age"] for i in v],
}
output.append(this_group)
pprint(output)
The output is:
[{'age': [12, 14, 16], 'name': 'Jane', 'school': 'SIT'},
{'age': [13], 'name': 'John', 'school': 'NUS'},
{'age': [13], 'name': 'John', 'school': 'SMU'}]
If you wish to go with the solution based on a buffer dictionary, please check out the dict.setdefault() method.
Example:
buffer = {}
for i in data:
buffer.setdefault((i["name"], i["school"]), []).append(i["age"])
For reference:
https://docs.python.org/3/library/itertools.html#itertools.groupby
https://docs.python.org/3/library/stdtypes.html#dict.setdefault
x = [{'name': 'Jane', 'age':12, 'school': 'SIT'}, {'name': 'John', 'age':13, 'school': 'SMU'},{'name': 'Jane', 'age':14, 'school': 'SIT'}, {'name': 'Jane', 'age':16, 'school': 'SIT'}, {'name': 'John', 'age':13, 'school': 'NUS'}]
new_x = {}
for r in x:
if r['name'] in new_x.keys():
if not isinstance(new_x[r['name']]['age'], list):
new_x[r['name']]['age'] = [new_x[r['name']]['age']]
if r['age'] not in new_x[r['name']]['age']:
new_x[r['name']]['age'].append(r['age'])
else:
new_x[r['name']] = {'age': r['age'], 'school': r['school']}
z = [v.update(name=k) for k, v in new_x.items()]
z = [v for k, v in new_x.items()]
Here is a universal solution to your problem. Only name and school are considered "special". All other keys, like age are converted to list when a new value has to be added.
l = [
{"name": "Jane", "age": 12, "school": "SIT"},
{"name": "John", "age": 13, "school": "SMU"},
{"name": "Jane", "age": 14, "school": "SIT"},
{"name": "Jane", "age": 16, "school": "SIT"},
{"name": "John", "age": 13, "school": "NUS"},
]
r = {}
for x in l:
id = f"{x['name']}-{x['school']}"
if id in r:
for k,v in x.items():
if k not in ["name", "school"]:
if k in r[id]:
if isinstance(r[id][k], list):
r[id][k].append(v)
else:
r[id][k] = [r[id][k], v]
else:
r[id][k] = v
else:
r[id] = x
result = [x for x in r.values()]

I am trying to do an update for a list of dictionaries in python

I have to update the list of dictionaries, more precisely: if the value is greater than 70 then the value associated then the key should be uppercase, otherwise if it is less than or equal to 70 it should be lowercase.
I tried to use a for loop but I get this error for k,v in list():
TypeError: 'list' object is not callable
This is what I have so far:
list = [{'brand':'nokia', "age":"56"}, {'brand':'motorola', "age":"80"}, {'brand':'sony', "age":"42"}, {'brand':'allview', "age":"10"}, {'brand':'huawei', "age":"15"}]
for k,v in list():
if v > 50:
list[k].upper()
else:
list[k].lower()
print = list()
Starting with the error that you're getting, it is because you need to iterate on the list elements first before using the key, value pair to iterate over dictionary items.
Now, if your list is:
my_list = [{'brand':'nokia', "age":"56"}, {'brand':'motorola', "age":"80"}, {'brand':'sony', "age":"42"}, {'brand':'allview', "age":"10"}, {'brand':'huawei', "age":"15"}]
Just run this code:
for my_dict in my_list:
age_value = int(my_dict["age"])
brand_value = my_dict["brand"]
if age_value > 70:
my_dict["brand"] = brand_value.upper()
else:
my_dict["brand"] = brand_value.lower()
and you'll get the result as:
[{'brand': 'nokia', 'age': '56'},
{'brand': 'MOTOROLA', 'age': '80'},
{'brand': 'sony', 'age': '42'},
{'brand': 'allview', 'age': '10'},
{'brand': 'huawei', 'age': '15'}]
PS - The usage of 'list' for your list is not recommended since it's a bad practice because 'list' is a data type, you should change it to something like 'my_list'.
what you want maybe:
s = [{'brand':'nokia', "age":"56"}, {'brand':'motorola', "age":"80"}, {'brand':'sony', "age":"42"}, {'brand':'allview', "age":"10"}, {'brand':'huawei', "age":"15"}]
[ {'brand': item['brand'].upper() if int(item['age'])>70 else item['brand'], 'AGE' if int(item['age']) > 70 else 'age': item['age']} for item in s]
the output is:
[{'brand': 'nokia', 'age': '56'}, {'brand': 'MOTOROLA', 'AGE': '80'}, {'brand': 'sony', 'age': '42'}, {'brand': 'allview', 'age': '10'}, {'brand': 'huawei', 'age': '15'}]
Given your code, I made the following solution providing an uppercase value of 'brand' if the age of the company is over 70.
list = [{'brand':'nokia', "age":"56"}, {'brand':'motorola', "age":"80"}, {'brand':'sony', "age":"42"}, {'brand':'allview', "age":"10"}, {'brand':'huawei', "age":"15"}]
#set the range n for index 0,n to the number of dictionary entries in your list.
for index in range(0,5):
print(list[index]["age"])
# if list([index]["age"])>70:
# print("old asF")
int_value = int(list[index]["age"])
#here we reassign the value of 'brand' to be 'brand'.upper()
if int_value >70:
list[index]['brand'] = list[index]['brand'].upper()
print(list)
gives the following output
[{'brand': 'nokia', 'age': '56'}, {'brand': 'MOTOROLA', 'age': '80'}, {'brand': 'sony', 'age': '42'}, {'brand': 'allview', 'age': '10'}, {'brand': 'huawei', 'age': '15'}]

How to exchange values inside a dict (based on Function Arguments)

Assuming the following dictionary in Python:
original_dict = {'place_01': 'Tom',
'place_02': 'John',
'place_03': 'Steve',
'place_04': 'Mark'}
I would like to define a function that allows me to exchange a defined pair values list.
My function should look like:
def change_position(mydict, change_from, change_to):
Passing the following arguments:
new_dict = change_position(original_dict, ['Tom','John'], ['Mark','Steve'])
Desidered result should be:
new_dict = {'place_01': 'Mark',
'place_02': 'Steve',
'place_03': 'John',
'place_04': 'Tom'}
basically:
'Tom' has been exchanged with 'Mark'
'John' has been exchanged Steve)
You can use a dictionary comprehension:
def change_position(mydict, c1, c2):
d = {**dict(zip(c1, c2)), **dict(zip(c2, c1))}
return {a:d[b] for a, b in mydict.items()}
original_dict = {'place_01': 'Tom', 'place_02': 'John', 'place_03': 'Steve', 'place_04': 'Mark'}
result = change_position(original_dict, ['Tom', 'John'], ['Mark', 'Steve'])
Output:
{'place_01': 'Mark', 'place_02': 'Steve', 'place_03': 'John', 'place_04': 'Tom'}
Requirement: values being unique in the dict
You need
a copy of my_dict to apply the changes
a reversed dict value > key to know where to apply the changes
Then iterate and swap
def change_position(mydict, change_from, change_to):
result = {**mydict}
mappings = {v: k for k, v in mydict.items()}
for val_from, val_to in zip(change_from, change_to):
key_from, key_to = mappings[val_from], mappings[val_to]
result[key_to], result[key_from] = mydict[key_from], mydict[key_to]
return result
Gives
original_dict = {'place_01': 'Tom', 'place_02': 'John', 'place_03': 'Steve', 'place_04': 'Mark'}
new_dict = change_position(original_dict, ['Tom', 'John'], ['Mark', 'Steve'])
print(new_dict) # {'place_01': 'Mark', 'place_02': 'Steve', 'place_03': 'John', 'place_04': 'Tom'}

how to create a new key from a value of another key Python

I have a list of dictionaries that looks like the following:
data = [{'Name': 'Paul', 'Date': '20200412', 'ID': '1020'}, {'Name': 'Frank', 'Date': '20200413', 'ID': '1030'}, {'Name': 'Anna', 'Date': '20200414', 'ID': '1040'}]
I need to create a new list of dictionaries, where ID's value would be the key, and the value is another dictionary with key/values associated with this specific ID.
This is the desired output:
new_data = [{'1020': {'Name': 'Paul', 'Date': '20200412'}},
{'1030': {'Name': 'Frank', 'Date': '20200413'}},
{'1040': {'Name': 'Anna', 'Date': '20200414'}}]
I have tried:
for index, my_dict in enumerate(data):
new_data = []
key = my_dict['ID']
new_data.append(key)
But that only assigned the key value, not sure how to push it into into a new dict along with other key/values.
>>> [{i['ID']: {k:v for k,v in i.items() if k != 'ID'}} for i in data]
[{'1020': {'Name': 'Paul', 'Date': '20200412'}},
{'1030': {'Name': 'Frank', 'Date': '20200413'}},
{'1040': {'Name': 'Anna', 'Date': '20200414'}}]
new_data = []
for index, my_dict in enumerate(data):
key = my_dict['ID']
del my_dict['ID']
new_data.append({key:data[index]})
To add the other values you simply need to create a new dict like this:
new_data.append( key:{
'name':my_dict['name']
'Date':my_dict['date']
}
You also don't need to make the 'key' variable, you can just use 'my_dict['ID']'
You could try this list comprehension:
[{x["ID"]: {k: v for k, v in x.items() if k != "ID"}} for x in data]
Which assigns ID as the parent key to the dictionary, and filters out the ID key from the child dictionary inside a dict comprehension
Which could be broken down into this:
result = []
for x in data:
result.append({x["ID"]: {k: v for k, v in x.items() if k != "ID"}})
And even to a straightforward loop approach:
result = []
for x in data:
dic = {x["ID"]: {}}
for k, v in x.items():
if k != "ID":
dic[x["ID"]][k] = v
result.append(dic)
Output:
[{'1020': {'Name': 'Paul', 'Date': '20200412'}}, {'1030': {'Name': 'Frank', 'Date': '20200413'}}, {'1040': {'Name': 'Anna', 'Date': '20200414'}}]

Create a list of dictionaries from a list of keys and multiple lists of values

My solution
keys = ['FirstName', 'LastName', 'ID']
name1 = ['Michael', 'Jordan', '224567']
name2 = ['Kyle', 'Hynes', '294007']
name3 = ['Josef', 'Jones', '391107']
dictList = []
dictList.append(dict(zip(keys, name1)))
dictList.append(dict(zip(keys, name2)))
dictList.append(dict(zip(keys, name3)))
Works fine, but is there any other solution, because I will have at least 20000 names, so I am looking how to improve this.
Place all your "name" sublists into the parent list names. Then you can easily use list comprehension:
keys = ['FirstName', 'LastName', 'ID']
names = [
['Michael', 'Jordan', '224567'],
['Kyle', 'Hynes', '294007'],
['Josef', 'Jones', '391107']
]
dictList = [{k:v for k,v in zip(keys, n)} for n in names]
print(dictList)
The output:
[{'FirstName': 'Michael', 'LastName': 'Jordan', 'ID': '224567'}, {'FirstName': 'Kyle', 'LastName': 'Hynes', 'ID': '294007'}, {'FirstName': 'Josef', 'LastName': 'Jones', 'ID': '391107'}]
Do you really need a dictionary? Why not just use a namedtuple:
>>> from collections import namedtuple
>>> Employee = namedtuple('Employee', 'FirstName, LastName, ID')
>>> names_list = [['Michael', 'Jordan', '224567'], ['Kyle', 'Hynes', '294007'], ['Josef', 'Jones', '391107']]
>>> employee_list = map(Employee._make, names_list)
>>> employee_list[0].FirstName
'Michael'
>>> pprint(employee_list)
[Employee(FirstName='Michael', LastName='Jordan', ID='224567'),
Employee(FirstName='Kyle', LastName='Hynes', ID='294007'),
Employee(FirstName='Josef', LastName='Jones', ID='391107')]
pandas makes this too easy.
import pandas as pd
keys = ['FirstName', 'LastName', 'ID']
name1 = ['Michael', 'Jordan', '224567']
name2 = ['Kyle', 'Hynes', '294007']
name3 = ['Josef', 'Jones', '391107']
doc_list = [name1,name2,name3]
df = pd.DataFrame(doc_list,columns = keys)
So you'll have a DataFrame like this:
FirstName LastName ID
0 Michael Jordan 224567
1 Kyle Hynes 294007
2 Josef Jones 391107
If your names are already in a file,read_csv would be better.
pd.read_csv("file_name.csv",header=keys)//remove the header parameter if it is present in your csv.
You should append your dictionaries to the list inside a loop, like this:
In [1152]: names = [name1, name2, name3]
In [1153]: d = []
In [1154]: for name in names:
...: d.append(dict(zip(keys, name)))
...:
In [1155]: d
Out[1155]:
[{'FirstName': 'Michael', 'ID': '224567', 'LastName': 'Jordan'},
{'FirstName': 'Kyle', 'ID': '294007', 'LastName': 'Hynes'},
{'FirstName': 'Josef', 'ID': '391107', 'LastName': 'Jones'}]
Or, if you prefer, a list comprehension:
In [1160]: d = [dict(zip(keys, name)) for name in names]
In [1161]: d
Out[1161]:
[{'FirstName': 'Michael', 'ID': '224567', 'LastName': 'Jordan'},
{'FirstName': 'Kyle', 'ID': '294007', 'LastName': 'Hynes'},
{'FirstName': 'Josef', 'ID': '391107', 'LastName': 'Jones'}]

Categories

Resources