remove a dict entry in a list of dict python - python

How can I remove a key in a dic in a list
for exemple
My_list= [{'ID':0,'Name':'Paul','phone':'1234'},{'ID':1,'Name':'John','phone':'5678'}]
I want to remove in ID 1 the phone key
My_list= [{'ID':0,'Name':'Paul','phone':'1234'},{'ID':1,'Name':'John'}]
thanks in advance for your help

Just iterate through the list, check whether if 'ID' equals to 1 and if so then delete the 'phone' key. This should work:
for d in My_list:
if d["ID"] == 1:
del d["phone"]
And finally print the list:
print My_list

When the id you are looking for matches 1, then reconstruct the dictionary excluding the key phone, otherwise use the dictionary as it is, like this
l = [{'ID': 0, 'Name': 'Paul', 'phone': '1234'},
{'ID': 1, 'Name': 'John', 'phone': '5678'}]
k, f = 1, {"phone"}
print([{k: i[k] for k in i.keys() - f} if i["ID"] == k else i for i in l])
# [{'phone': '1234', 'ID': 0, 'Name': 'Paul'}, {'ID': 1, 'Name': 'John'}]
Here, k is the value of ID you are looking for and f is a set of keys which need to be excluded in the resulting dictionary, if the id matches.

Related

Compare two dictionary lists, based on specific key

I'll try to be the more concise that I can.
Two dictionary lists as follows:
dictlist1 = [{'name': 'john', 'age': 30}, {'name': 'jessica', 'age': 56}, {'name': 'kirk', 'age': 20}, {'name': 'mario, 'age': 25}]
dictlist2 = [{'name': 'john', 'job': 'engineer'}, {'name': 'jessica', 'job':'nurse'}, {'name': 'mario', 'job': 'electrician'}]
My objective is to match base on the key "name" on both dictionaries and, at the end, create a third dictionary list with the key that has no match, in this case {'name':'kirk' , 'age':20}, like this:
listfinal = [{'name': 'kirk', 'age': 20}]
I've tried successfully compare the equal keys, creating a new dictionary with keys that matches and adding "job" key to it, doing this:
for dict2 in dictlist2:
for dict1 in dictlist1:
if dict1['name'] == dict2['name']:
matchname1 = dict2['name']
dictoutput = {'name': matchname1, 'age': dict1['age'], 'group': dict2['group']}
templist.append(dictoutput)
for dictionay in templist:
print(dictionay)
Output:
{'name': 'john', 'age': '30', 'job': 'engineer'}
{'name': 'jessica', 'age': '56', 'job': 'nurse'}
{'name': 'mario', 'age': '25', 'job': 'electrician'}
But absolutely no luck to get kirk user alone, not even using "else" in the inner if statement or creating a new if statement and using not equal (!=). I always get all the users when printing.
Any orientation will be highly appreciated.
Enumerate the lists and then collect the indices of matched pairs in a list inside the loop and delete corresponding elements outside the loop.
matched_d1 = []
matched_d2 = []
for j2, dict2 in enumerate(dictlist2):
for j1, dict1 in enumerate(dictlist1):
if dict1['name'] == dict2['name']:
matchname1 = dict2['name']
dictoutput = {'name': matchname1, 'age': dict1['age'], 'group': dict2['group']}
templist.append(dictoutput)
matched_d1.append(j1)
matched_d2.append(j2)
for j in sorted(matched_d1, reverse = True):
dictlist1.pop(j)
for j in sorted(matched_d2, reverse = True):
dictlist2.pop(j)
ans = dictlist1 + dictlist2
You can use sets to find the names that are only in dictlist1, in dictlist2 and also the common names. Then create the listfinal by keeping only the item with the name not in the common names:
dictlist1 = [{"name": "john", "age": 30}, {"name": "jessica", "age": 56}, {"name":"kirk" , "age": 20}, {"name": "mario", "age": 25}]
dictlist2 = [{"name": "john", "job": "engineer"}, {"name": "jessica", "job": "nurse"}, {"name": "mario", "job": "electrician"}]
names_dictlist1 = {item["name"] for item in dictlist1}
names_dictlist2 = {item["name"] for item in dictlist2}
common_names = names_dictlist1 & names_dictlist2
listfinal = [item for item in dictlist1 + dictlist2 if item["name"] not in common_names]
If you want one-line solution there it is
print([person for person in dictlist1 if person['name'] not in map(lambda x: x['name'], dictlist2)])
This code prints element from fist list wich "name" key doesnt occur in second list
you can use set operations to get the unique name, first make a set of the names on each one and subtract both, then use that to get the appropriate item form the list
>>> name1 = set(d["name"] for d in dictlist1)
>>> name2 = set(d["name"] for d in dictlist2)
>>> name1 - name2
{'kirk'}
>>> name2 - name1
set()
>>> unique = name1 - name2
>>> listfinal = [d for n in unique for d in dictlist1 if d["name"]==n]
>>> listfinal
[{'name': 'kirk', 'age': 20}]
>>>
Additionally, looking at #freude answers, you can make it a dictionary of name:index for each list an subtracts its keys, given that they dict.keys behave set-like in order to avoid a double loop from before to get the right item from the list
>>> name1 = {d["name"]:i for i,d in enumerate(dictlist1)}
>>> name2 = {d["name"]:i for i,d in enumerate(dictlist2)}
>>> unique = name1.keys() - name2.keys()
>>> unique
{'kirk'}
>>> [ dictlist1[name1[n]] for n in unique]
[{'name': 'kirk', 'age': 20}]
>>>

Deleting an element from a list inside a dict in Python

{
'tbl':'test',
'col':[
{
'id':1,
'name':"a"
},
{
'id':2,
'name':"b"
},
{
'id':3,
'name':"c"
}
]
}
I have a dictionary like the one above and I want to remove the element with id=2 from the list inside it. I wasted half a day wondering why modify2 is not working with del operation. Tried pop and it seems to be working but I don't completely understand why del doesn't work.
Is there a way to delete using del or pop is the ideal way to address this use case?
import copy
test_dict = {'tbl': 'test', 'col':[{'id':1, 'name': "a"}, {'id':2, 'name': "b"}, {'id':3, 'name': "c"}]}
def modify1(dict):
new_dict = copy.deepcopy(dict)
# new_dict = dict.copy()
for i in range(len(dict['col'])):
if dict['col'][i]['id'] == 2:
new_dict['col'].pop(i)
return new_dict
def modify2(dict):
new_dict = copy.deepcopy(dict)
# new_dict = dict.copy()
for i in new_dict['col']:
if i['id']==2:
del i
return new_dict
print("Output 1 : " + str(modify1(test_dict)))
print("Output 2 : " + str(modify2(test_dict)))
Output:
Output 1 : {'tbl': 'test', 'col': [{'id': 1, 'name': 'a'}, {'id': 3, 'name': 'c'}]}
Output 2 : {'tbl': 'test', 'col': [{'id': 1, 'name': 'a'}, {'id': 2, 'name': 'b'}, {'id': 3, 'name': 'c'}]}
I tried looking for answers on similar questions but didn't find the one that clears my confusion.
In Python 3, you can do this:
test_dict = {**test_dict, 'col': [x for x in test_dict['col'] if x['id'] != 2]}
del i just tells the interpreter that i (an arbitrary local variable/name that happens to reference to a dictionary) should not reference that dictionary any more. It does not change the content of that dictionary whatsoever.
This can be visualized on http://www.pythontutor.com/visualize.html:
Before del i. Note i references the second dictionary (noted by the blue line):
After del i. Note how the local variable i is removed from the local namespace (the blue box) but the dictionary it referenced to still exists.
Contrary to del i (which modifies the reference to the dictionary), dict.pop(key) modifies the dictionary.
This is one approach using a comprehension.
Ex:
data = {'tbl': 'test', 'col': [{'id': 1, 'name': 'a'}, {'id': 2, 'name': 'b'}, {'id': 3, 'name': 'c'}]}
data['col'] = [i for i in data['col'] if i["id"] != 2]
print(data)
Output:
{'col': [{'id': 1, 'name': 'a'}, {'id': 3, 'name': 'c'}], 'tbl': 'test'}
The reason it is not working is that you are using del wrong.
If you have a dictionary d = {'a': [{'id':1}, {'id':2}]} Then to delete the second element of the dictionary you use del d['a'][1] this returns
d = {'a': [{'id':1}]}
So for your problem you iterate to find the position of id 2 in the list and then you can simply do del dict['col'][ix] where ix is the index of id 2 in the list
You can't delete an element referenced by the iterating variable (the i)in the for loop
l = [1,2,3]
for i in l:
if i == 2:
del i
won't work. l will still be [1,2,3]
what you can do is get the index of that element and delete by using the index
l = [1,2,3]
for idx, elem in enumerate(l):
if elem == 2:
del l[idx]

Generate list from two different lists by key

Considering the following structure:
myObj1 = [{"id":1, "name":"john"},
{"id":2, "name":"roger"},
{"id":3, "name":"carlos"}]
myObj2 = [{"group": "myGroup1","persons":[1, 2, 3]},
{"group": "myGroup2", "persons":[2]},
{"group": "myGroup3", "persons":[1,3]}]
I would like the produce the following result:
result = [{"group": "myGroup1","persons":[{"id":1, "name":"john"},
{"id":2, "name":"roger"},
{"id":3, "name":"carlos"}]},
{"group": "myGroup2", "persons":[{"id":2, "name":"roger"}]},
{"group": "myGroup3", "persons":[{"id":1, "name":"john"},
{"id":3, "name":"carlos"}]}]
The challenge is for each value in the "persons" array substitute it for the entire myObj1 item value where the id matches.
I could achieve that using like 3 for's but I want to know if there's a pythonic way of doing this using interpolation, map, filter, sets and etc.. I'm knew to the python word but got this question from an interviewer and he told me that I was supposed to do that with 1-2 lines of code.
UPDATE:
Here's what was my newbie approach:
for item in myObj1:
id = item["id"]
for item2 in myObj2:
for i in range(len(item2["persons"])):
if item2["persons"][i] == id:
item2["persons"][i] = item
result = myObj2.copy()
for d in result:
d['persons'] = [[j for j in myObj1 if j['id']==i][0] for i in d['persons']]
result
Output:
[{'group': 'myGroup1',
'persons': [{'id': 1, 'name': 'john'},
{'id': 2, 'name': 'roger'},
{'id': 3, 'name': 'carlos'}]},
{'group': 'myGroup2', 'persons': [{'id': 2, 'name': 'roger'}]},
{'group': 'myGroup3',
'persons': [{'id': 1, 'name': 'john'}, {'id': 3, 'name': 'carlos'}]}]
How about the following:
result = [dict(x) for x in myObj2]
for grp in result:
grp["persons"] = [p for p in myObj1 if p["id"] in grp["persons"]]
We create a new list (using dict(x) to ensure we don't retain references to the elements ofmyObj2`), and then update accordingly.
You can try this:
myObj1 = [{"id":1, "name":"john"},
{"id":2, "name":"roger"},
{"id":3, "name":"carlos"}]
myObj2 = [{"group": "myGroup1","persons":[1, 2, 3]},
{"group": "myGroup2", "persons":[2]},
{"group": "myGroup3", "persons":[1,3]}]
final_dict = [{a:b if a != "persons" else c for a,b in d.items()} for c, d in zip(myObj1, myObj2)]
Output:
[{'persons': {'id': 1, 'name': 'john'}, 'group': 'myGroup1'}, {'persons': {'id': 2, 'name': 'roger'}, 'group': 'myGroup2'}, {'persons': {'id': 3, 'name': 'carlos'}, 'group': 'myGroup3'}]
What you're trying to do is essentially a group by operation followed by mapping over dictionary values. This is an example of where the itertools module really shines.
from itertools import chain, groupby
def concat(lists):
"""
Helper function to make concatenating lists/iterables easier
"""
return list(chain.from_iterable(lists))
by_group = {
id: list(people)
for id, people in groupby(myObj1, key=lambda person: person['id'])
}
result = [
{'group': group['group'],
'persons': concat(by_group[id] for id in group['persons'])}
for group in myObj2
]
In this example, you still need the for-loops, but it is now clear what those loops are trying to do. The first is making an intermediate data structure to keep track of who has what id. The second is then going through another data structure and calculating who's in what group based on the groupby operation.
one approach is to substitute the values for the "persons" key, like this:
[group.update({'persons':[myObj1[next(index for (index, d) in enumerate(myObj1) if d["id"] == idstud)] for idstud in group['persons'] if idstud in [i['id'] for i in myObj1]]}) for group in myObj2]

Python - Get dictionary element in a list of dictionaries after an if statement

How can I get a dictionary value in a list of dictionaries, based on the dictionary satisfying some condition? For instance, if one of the dictionaries in the list has the id=5, I want to print the value corresponding to the name key of that dictionary:
list = [{'name': 'Mike', 'id': 1}, {'name': 'Ellen', 'id': 5}]
id = 5
if any(m['id'] == id for m in list):
print m['name']
This won't work because m is not defined outside the if statement.
You have a list of dictionaries, so you can use a list comprehension:
[d for d in lst if d['id'] == 5]
# [{'id': 5, 'name': 'Ellen'}]
new_list = [m['name'] for m in list if m['id']==5]
print '\n'.join(new_list)
This will be easy to accomplish with a single for-loop:
for d in list:
if 'id' in d and d['in'] == 5:
print(d['name'])
There are two key concepts to learn here. The first is that we used a for loop to "go through each element of the list". The second, is that we used the in word to check if a dictionary had a certain key.
How about the following?
for entry in list:
if entry['id']==5:
print entry['name']
It doesn't exist in Python2, but a simple solution in Python3 would be to use a ChainMap instead of a list.
import collections
d = collections.ChainMap(*[{'name':'Mike', 'id': 1}, {'name':'Ellen', 'id': 5}])
if 'id' in d:
print(d['id'])
You can do it by using the filter function:
lis = [ {'name': 'Mike', 'id': 1}, {'name':'Ellen', 'id': 5}]
result = filter(lambda dic:dic['id']==5,lis)[0]['name']
print(result)

python list of dictionaries find duplicates based on value

I have a list of dicts:
a =[{'id': 1,'desc': 'smth'},
{'id': 2,'desc': 'smthelse'},
{'id': 1,'desc': 'smthelse2'},
{'id': 1,'desc': 'smthelse3'}]
I would like to go trough the list and find those dicts that have the same id value (e.g. id=1) and create a new dict:
b = [{'id':1, 'desc' : [smth, smthelse2,smthelse3]},
{'id': 2, 'desc': 'smthelse'}]
You can try:
import operator, itertools
key = operator.itemgetter('id')
b = [{'id': x, 'desc': [d['desc'] for d in y]}
for x, y in itertools.groupby(sorted(a, key=key), key=key)]
It is better to keep the "desc" values as lists everywhere even if they contain a single element only. This way you can do
for d in b:
print d['id']
for desc in d['desc']:
print desc
This would work for strings too, just returning individual characters, which is not what you want.
And now the solution giving you a list of dicts of lists:
a =[{'id': 1,'desc': 'smth'},{'id': 2,'desc': 'smthelse'},{'id': 1,'desc': 'smthelse2'},{'id': 1,'desc': 'smthelse3'}]
c = {}
for d in a:
c.setdefault(d['id'], []).append(d['desc'])
b = [{'id': k, 'desc': v} for k,v in c.iteritems()]
b is now:
[{'desc': ['smth', 'smthelse2', 'smthelse3'], 'id': 1},
{'desc': ['smthelse'], 'id': 2}]
from collections import defaultdict
d = defaultdict(list)
for x in a:
d[x['id']].append(x['desc']) # group description by id
b = [dict(id=id, desc=desc if len(desc) > 1 else desc[0])
for id, desc in d.items()]
To preserve order:
b = []
for id in (x['id'] for x in a):
desc = d[id]
if desc:
b.append(dict(id=id, desc=desc if len(desc) > 1 else desc[0]))
del d[id]

Categories

Resources