I have the following two lists of dictionaries:
list_1 = [
{'id': '1', 'name': 'Johnny Johson1'},
{'id': '2', 'name': 'Johnny Johson2'},
{'id': '1', 'name': 'Johnny Johson1'},
{'id': '3', 'name': 'Johnny Johson3'},
]
list_2 = [
{'id': '1', 'datetime': '2020-01-06T12:30:00.000Z'},
{'id': '2', 'datetime': '2020-01-06T14:00:00.000Z'},
{'id': '1', 'datetime': '2020-01-06T15:30:00.000Z'},
{'id': '3', 'datetime': '2020-01-06T15:30:00.000Z'},
]
Essentially, I would like no loss of data even on duplicate IDs, as they represent different events (there is a sepearate ID for that, but for the purpose of demonstrating the problem, is not needed). If there are any IDs in one list, not in the other, then disregard that ID all together.
Ideally, I would like to end up with the following (from the amalgamation of the two lists):
list_3 = [
{'id': '1', 'name': 'Johnny Johson1', 'datetime': '2020-01-06T12:30:00.000Z'},
{'id': '2', 'name': 'Johnny Johson2', 'datetime': '2020-01-06T14:00:00.000Z'},
{'id': '1', 'name': 'Johnny Johson1', 'datetime': '2020-01-06T15:30:00.000Z'},
{'id': '3', 'name': 'Johnny Johson3', 'datetime': '2020-01-06T15:30:00.000Z'},
]
You can use the following list comprehension, which uses the double asterisk keyword argent unpacking syntax, evaluated on both lists using pairwise elements obtained with zip(). This has the effect of combining the two dictionaries into one.
list_3 = [{**x, **y} for x, y in zip(list_1, list_2)]
Output:
>>> list3
[{'id': '1', 'name': 'Johnny Johson1', 'datetime': '2020-01-06T12:30:00.000Z'},
{'id': '2', 'name': 'Johnny Johson2', 'datetime': '2020-01-06T14:00:00.000Z'},
{'id': '1', 'name': 'Johnny Johson1', 'datetime': '2020-01-06T15:30:00.000Z'},
{'id': '3', 'name': 'Johnny Johson3', 'datetime': '2020-01-06T15:30:00.000Z'}]
Note that this approach requires at least Python 3.5.
Related
List1 = ["1-Delphinia-65.61.138.207",
"2-Lennie-74.37.240.220",
"3-Shayne-174.76.131.156",
"4-Veriee-59.20.115.49",
"5-Val-172.101.94.229",
"6-Lanny-1.16.47.151",
"7-Laureen-117.2.197.11",
"8-Kristyn-63.21.195.62",
"9-Arlana-92.84.0.112",
"10-Arney-49.145.219.15"]
Transform the list into a dictionary with items in the following format
{
“Delphine” : {
“id” : 1,
“Ipaddr”: 65.61.138.207
},
“Lennie” : { ……. },
…….
}
Use dictionary comperhension:
>>> {name: {'id': int(id_), 'Ipaddr': ipaddr} for id_, name, ipaddr in map(lambda s: s.split('-'), List1)}
{'Delphinia': {'id': 1, 'Ipaddr': '65.61.138.207'},
'Lennie': {'id': 2, 'Ipaddr': '74.37.240.220'},
'Shayne': {'id': 3, 'Ipaddr': '174.76.131.156'},
'Veriee': {'id': 4, 'Ipaddr': '59.20.115.49'},
'Val': {'id': 5, 'Ipaddr': '172.101.94.229'},
'Lanny': {'id': 6, 'Ipaddr': '1.16.47.151'},
'Laureen': {'id': 7, 'Ipaddr': '117.2.197.11'},
'Kristyn': {'id': 8, 'Ipaddr': '63.21.195.62'},
'Arlana': {'id': 9, 'Ipaddr': '92.84.0.112'},
'Arney': {'id': 10, 'Ipaddr': '49.145.219.15'}}
Other approach, using a dictionary comprehension:
{name: {'id': ID, 'Ipaddr': ip} for s in List1 for ID, name, ip in [s.split('-')]}
output:
{'Delphinia': {'id': '1', 'Ipaddr': '65.61.138.207'},
'Lennie': {'id': '2', 'Ipaddr': '74.37.240.220'},
'Shayne': {'id': '3', 'Ipaddr': '174.76.131.156'},
'Veriee': {'id': '4', 'Ipaddr': '59.20.115.49'},
'Val': {'id': '5', 'Ipaddr': '172.101.94.229'},
'Lanny': {'id': '6', 'Ipaddr': '1.16.47.151'},
'Laureen': {'id': '7', 'Ipaddr': '117.2.197.11'},
'Kristyn': {'id': '8', 'Ipaddr': '63.21.195.62'},
'Arlana': {'id': '9', 'Ipaddr': '92.84.0.112'},
'Arney': {'id': '10', 'Ipaddr': '49.145.219.15'}}
You can simply use this code:
List1 = ["1-Delphinia-65.61.138.207", "2-Lennie-74.37.240.220", "3-Shayne-174.76.131.156", "4-Veriee-59.20.115.49", "5-Val-172.101.94.229", "6-Lanny-1.16.47.151", "7-Laureen-117.2.197.11", "8-Kristyn-63.21.195.62", "9-Arlana-92.84.0.112", "10-Arney-49.145.219.15"]
final_dict = {}
for item in List1:
data = item.split('-')
final_dict[data[1]] = {'id':int(data[0]), 'Ipaddr': data[2]}
print(final_dict)
This is how I'd do it with my basic python knowledge
new_dict= {}
for item in List1:
newitem=item.split("-")
new_dict[newitem[1]]={'id':int(newitem[0]),'ip':newitem[2]}
print(new_dict)
Output is
{
"Delphinia":{
"id":1,
"ip":"65.61.138.207"
},
"Lennie":{
"id":2,
"ip":"74.37.240.220"
},
"Shayne":{
"id":3,
"ip":"174.76.131.156"
},
"Veriee":{
"id":4,
"ip":"59.20.115.49"
},
"Val":{
"id":5,
"ip":"172.101.94.229"
},
"Lanny":{
"id":6,
"ip":"1.16.47.151"
},
"Laureen":{
"id":7,
"ip":"117.2.197.11"
},
"Kristyn":{
"id":8,
"ip":"63.21.195.62"
},
"Arlana":{
"id":9,
"ip":"92.84.0.112"
},
"Arney":{
"id":10,
"ip":"49.145.219.15"
}
def Convert(lst):
res_dct = {lst[i+1]: {"id":lst[i],"Ipaddr":lst[i + 2]} for i in range(0,len(lst), 3)}
return res_dct
final_dict ={}
for i in list1:
l =(i.split('-'))
new = Convert(l)
final_dict.update(new)
output >> final_dict
{'Delphinia': {'id': '1', 'Ipaddr': '65.61.138.207'},
'Lennie': {'id': '2', 'Ipaddr': '74.37.240.220'},
'Shayne': {'id': '3', 'Ipaddr': '174.76.131.156'},
'Veriee': {'id': '4', 'Ipaddr': '59.20.115.49'},
'Val': {'id': '5', 'Ipaddr': '172.101.94.229'},
'Lanny': {'id': '6', 'Ipaddr': '1.16.47.151'},
'Laureen': {'id': '7', 'Ipaddr': '117.2.197.11'},
'Kristyn': {'id': '8', 'Ipaddr': '63.21.195.62'},
'Arlana': {'id': '9', 'Ipaddr': '92.84.0.112'},
'Arney': {'id': '10', 'Ipaddr': '49.145.219.15'}}
My two dictionaries look like this
list1 = [{'time': '2020', 'name': 'one', 'address': '15423'},{'time': '2021', 'name': 'two', 'address': '8548305'}]
list2 = [{'to': '15423', 'value': '5'}, {'to': '8548305', 'value': '90'}, {'to': '123', 'value': '5'}]
I want my final list of dictionaries to look like this. Also, I don't want to consider dictionary if it doesn't have a match from another list of dictionaries
list3 = [{'time': '2020', 'name': 'one', 'address': '15423', 'value': '5'}, {'time': '2021', 'name': 'two', 'address': '8548305', 'value': '90'}]
Here is what I tried
[lst1.update(lst2) for lst1, lst2 in zip(list1, list2)]
But I don't know how can I group by address.
Appreciate your help
You are on the right track. You can do something like:
[{**lst1 , **lst2} for lst1 in list1 for lst2 in list2 if lst1["address"] == lst2["address"]]
Output
[{'address': '15423', 'name': 'one', 'time': '2020', 'value': '5'},
{'address': '8548305', 'name': 'two', 'time': '2021', 'value': '90'}]
Note that, list comprehension might not be the best idea, since it lacks break and continue commands. Maybe it's more efficient to something like:
for index,lst1 in enumerate(list1):
for lst2 in list2:
if lst2["address"] == lst1["address"]:
list1[index]["value"] = lst2["value"]
break
list1
Output
[{'address': '15423', 'name': 'one', 'time': '2020', 'value': '5'},
{'address': '8548305', 'name': 'two', 'time': '2021', 'value': '90'}]
I have a list of dictionaries that I am wanting to convert to a nested list with the first element of that list(lst[0]) containing the dictionary keys and the rest of the elements of the list containing values for each dictionary.
[{'id': '123',
'name': 'bob',
'city': 'LA'},
{'id': '321',
'name': 'sally',
'city': 'manhattan'},
{'id': '125',
'name': 'fred',
'city': 'miami'}]
My expected output result is:
[['id','name','city'], ['123','bob','LA'],['321','sally','manhattan'],['125','fred','miami']]
What would be a way to go about this? Any help would be greatly appreciated.
you can use:
d = [{'id': '123',
'name': 'bob',
'city': 'LA'},
{'id': '321',
'name': 'sally',
'city': 'manhattan'},
{'id': '125',
'name': 'fred',
'city': 'miami'}]
[[k for k in d[0].keys()], *[list(i.values()) for i in d ]]
output:
[['id', 'name', 'city'],
['123', 'bob', 'LA'],
['321', 'sally', 'manhattan'],
['125', 'fred', 'miami']]
first, you get a list with your keys then get a list with the values for every inner dict
>>> d = [{'id': '123',
'name': 'bob',
'city': 'LA'},
{'id': '321',
'name': 'sally',
'city': 'manhattan'},
{'id': '125',
'name': 'fred',
'city': 'miami'}]
>>> [list(x[0].keys())]+[list(i.values()) for i in d]
[['id', 'name', 'city'], ['123', 'bob', 'LA'], ['321', 'sally', 'manhattan'], ['125', 'fred', 'miami']]
Serious suggestion: To avoid the possibility of some dicts having a different iteration order, base the order off the first entry and use operator.itemgetter to get a consistent order from all entries efficiently:
import operator
d = [{'id': '123',
'name': 'bob',
'city': 'LA'},
{'id': '321',
'name': 'sally',
'city': 'manhattan'},
{'id': '125',
'name': 'fred',
'city': 'miami'}]
keys = list(d[0])
keygetter = operator.itemgetter(*keys)
result = [keys, *[list(keygetter(x)) for x in d]] # [keys, *map(list, map(keygetter, d))] might be a titch faster
If a list of tuples is acceptable, this is simpler/faster:
keys = tuple(d[0])
keygetter = operator.itemgetter(*keys)
result = [keys, *map(keygetter, d)]
Unserious suggestion: Let csv do it for you!
import csv
import io
dicts = [{'id': '123',
'name': 'bob',
'city': 'LA'},
{'id': '321',
'name': 'sally',
'city': 'manhattan'},
{'id': '125',
'name': 'fred',
'city': 'miami'}]
with io.StringIO() as sio:
writer = csv.DictWriter(sio, dicts[0].keys())
writer.writeheader()
writer.writerows(dicts)
sio.seek(0)
result = list(csv.reader(sio))
Try it online!
This can be done with for loop and enumerate() built-in method.
listOfDicts = [
{"id": "123", "name": "bob", "city": "LA"},
{"id": "321", "name": "sally", "city": "manhattan"},
{"id": "125", "name": "fred", "city": "miami"},
]
results = []
for index, dic in enumerate(listOfDicts, start = 0):
if index == 0:
results.append(list(dic.keys()))
results.append(list(dic.values()))
else:
results.append(list(dic.values()))
print(results)
output:
[['id', 'name', 'city'], ['123', 'bob', 'LA'], ['321', 'sally', 'manhattan'], ['125', 'fred', 'miami']]
Assuming a list of dictionaries with unequal length, what's the best way to make them equal length i.e. for the missing key-value, add key but with value set to empty string or null:
lst = [
{'id': '123', 'name': 'john'},
{'id': '121', 'name': 'jane'},
{'id': '121'},
{'name': 'mary'}
]
to become:
lst = [
{'id': '123', 'name': 'john'},
{'id': '121', 'name': 'jane'},
{'id': '121', 'name': ''},
{'id': '', 'name': 'mary'}
]
The only way I can think of is converting to pandas dataframe then back to dict:
pd.DataFrame(lst).to_dict(orient='records')
Finding all the keys requires a full initial pass of the data:
>>> set().union(*lst)
{'id', 'name'}
Now iterate the dicts and set default for each key:
keys = set().union(*lst)
for d in lst:
for k in keys:
d.setdefault(k, '')
You could use colleections.ChainMap to get all the keys:
>>> lst = [
... {'id': '123', 'name': 'john'},
... {'id': '121', 'name': 'jane'},
... {'id': '121'},
... {'name': 'mary'}
... ]
>>>
>>> from collections import ChainMap
>>>
>>> for k in ChainMap(*lst):
... for d in lst:
... _ = d.setdefault(k, '')
...
>>> lst
[{'id': '123', 'name': 'john'}, {'id': '121', 'name': 'jane'}, {'id': '121', 'name': ''}, {'name': 'mary', 'id': ''}]
Try using this snippet
lst = [
{'id': '123', 'name': 'john'},
{'id': '121', 'name': 'jane'},
{'id': '121'},
{'name': 'mary'}
]
for data in lst:
if "name" not in data:
data["name"] = ""
if "id" not in data:
data["id"] = ""
print(lst)
Here's one way (Python 3.5+).
>>> all_keys = set(key for d in lst for key in d)
>>> [{**dict.fromkeys(all_keys, ''), **d} for d in lst]
[{'id': '123', 'name': 'john'}, {'id': '121', 'name': 'jane'}, {'id': '121', 'name': ''}, {'id': '', 'name': 'mary'}]
(Note that the unpacking order is critical here, you must unpack d after the dictionary with the default values in order to override the default values.)
I am trying to join a dictionary to another dictionary. I have two keys; one that is unique and another which is not unique. I want to join information on the non-unique key and leave all information as it is one the unique key, i.e. the number of unique id's has to stay the same.
Any ideas to how I can achieve this?
This is the first dictionary:
names = [
{'id': '1', 'name': 'Peter', 'category_id': '25'},
{'id': '2', 'name': 'Jim', 'category_id': '20'},
{'id': '3', 'name': 'Toni', 'category_id': '20'}
]
This is the second dictionary:
categories = [
{'category_id': '25', 'level': 'advanced'},
{'category_id': '20', 'level': 'beginner'}
]
And this is what I am trying to achieve:
all = [
{'id': '1', 'name': 'Peter', 'category_id': '25', 'level': 'advanced'},
{'id': '2', 'name': 'Jim', 'category_id': '20', 'level': 'beginner'},
{'id': '3', 'name': 'Toni', 'category_id': '20', 'level': 'beginner'}
]
EDIT:
names = [
{'id': '1', 'name': 'Peter', 'category_id': '25'},
{'id': '2', 'name': 'Jim', 'category_id': '20'},
{'id': '3', 'name': 'Toni', 'category_id': '20'}
]
categories = [
{'category_id': '25', 'level': 'advanced'},
{'category_id': '20', 'level': 'beginner'}
]
def merge_lists(l1, l2, key):
merged = {}
for item in l1+l2:
if item[key] in merged:
merged[item[key]].update(item)
else:
merged[item[key]] = item
return merged.values()
courses = merge_lists(names, categories, 'category_id')
print(courses)
gives:
([{'id': '1', 'name': 'Peter', 'category_id': '25', 'level': 'advanced'},
{'id': '3', 'name': 'Toni', 'category_id': '20', 'level': 'beginner'}])
Create a mapping from category_id to additional field(s), then combine the dictionaries in a loop, e.g:
cat = {d["category_id"]: d for d in categories}
res = []
for name in names:
x = name.copy()
x.update(cat[name["category_id"]])
res.append(x)
In Python 3.5+ you can use the cool new syntax:
cat = {d["category_id"]: d for d in categories}
res = [{**name, **cat[name["category_id"]]} for name in names]
Consider what you really want to do: add the level associated with each category to the names dict. So first, create a mapping from the categories to the associated levels:
cat_dict = {d['category_id']: d['level'] for d in categories}
It's then a trivial transformation on each dict in the names list:
for d in names:
d['level'] = cat_dict[d['category_id']]
The resulting names list is:
[{'category_id': '25', 'id': '1', 'level': 'advanced', 'name': 'Peter'},
{'category_id': '20', 'id': '2', 'level': 'beginner', 'name': 'Jim'},
{'category_id': '20', 'id': '3', 'level': 'beginner', 'name': 'Toni'}]