I am solving a specific problem and I would like to find out what is the most pythonic way. I have two list of dictionaries, for example:
l1 = [{id: '1', grade: 'A'}, {id: '2', grade: 'B'}, {id: '3', grade: 'A'}]
l2 = [{id: '1', grade: 'A'}, {id: '2', grade: 'B'}, {id: '3', grade: 'Unavailable'}]
There are always the same ids in boths lists, only the grades differ. Now I want to write a list comprehension to remove from l1 all the dictionaries that have Unavailable grade in l2. Meaning in this case I want to remove dict with id:3. Can someone help me out? Much thanks
CodePudding user response:
This works assuming l1 and l2 are of the same length. Try:
for dicIndex in range(len(l1)):
if 'Unavailable' in l2[dicIndex].values():
l1.pop(dicIndex)
print(l1)
Output:
[{'id': '1', 'grade': 'A'}, {'id': '2', 'grade': 'B'}]
CodePudding user response:
You could make an intermediate set of the ids you want to remove.
>>> l1 = [{'id': '1', 'grade': 'A'}, {'id': '2', 'grade': 'B'}, {'id': '3', 'grade': 'A'}]
>>> l2 = [{'id': '1', 'grade': 'A'}, {'id': '2', 'grade': 'B'}, {'id': '3', 'grade': 'Unavailable'}]
>>> unavailable = {g['id'] for g in l2 if g['grade'] == 'Unavailable'}
>>> l1_fixed = [g for g in l1 if g['id'] not in unavailable]
>>> l1_fixed
[{'id': '1', 'grade': 'A'}, {'id': '2', 'grade': 'B'}]
CodePudding user response:
You can do this with zip
,
In [1]: [d1 for d1,d2 in zip(l1, l2) if d2.get('grade') != 'Unavailable']
Out[1]: [{'id': '1', 'grade': 'A'}, {'id': '2', 'grade': 'B'}]
If the list is not ordered so we need to sort before the list comprehension,
l1 = sorted(l1, key=lambda x:x.get('id'))
l2 = sorted(l2, key=lambda x:x.get('id'))
output = [d1 for d1,d2 in zip(l1, l2) if d2.get('grade') != 'Unavailable']
CodePudding user response:
I believe this is the Pythonic way to do it
Using List Comprehension:
l1 = [{"id": '1', "grade": 'A'}, {"id": '2', "grade": 'B'}, {"id": '3', "grade": 'A'}]
l2 = [{"id": '1', "grade": 'A'}, {"id": '2', "grade": 'B'}, {"id": '3', "grade": 'Unavailable'}]
# Incase grade is always the same in l1 and l2
# Except it can have a value "Unavailable" in l2
l1 = [item for item in l2 if item['grade'] != 'Unavailable']
# Otherwise if grade can be a different value in both lists for the same index
l1 = [l1[i] for i in range(len(l2)) if l2[i]["grade"] != 'Unavailable']
Output:
>>> [{'id': '1', 'grade': 'A'}, {'id': '2', 'grade': 'B'}] # l1_method_1
>>> [{'id': '1', 'grade': 'A'}, {'id': '2', 'grade': 'B'}] # l1_method_2
CodePudding user response:
The simplest way I can think of that doesn't make assumptions.
>>> [m for m in l1 if m['id'] not in (n['id'] for n in l2 if n['grade'] == 'Unavailable')]
[{'id': '1', 'grade': 'A'}, {'id': '2', 'grade': 'B'}]