Intersection of two lists of dict - Python - python

I have two lists of dict
listA = [{'id': 'abc', 'key1': '542696d8485b'}]
listB = [{'id': 'abc', 'key1': '542696d8485b'}, {'id': 'def', 'key1': '27348628grn'}]
I want to extract listC = [{'id': 'abc', 'key1': '542696d8485b'}]
i.e I want to find intersection based on 'id' field( based on any one field, assuming common items in list are exactly same ). Suggest me some efficient pythonic way...
How about something like
listA_set = set(item['id'] for item in listA)
listB_set = set(item['id'] for item in listB)
listC_set = listA_set & listB_set
listC = {item:listA[item] for item in listC_set}

Why not use list comprehension:
listA = [{'id': 'abc', 'key1': '542696d8485b'}]
listB = [{'id': 'abc', 'key1': '542696d8485b'}, {'id': 'def', 'key1': '27348628grn'}]
print [i for i in listA for j in listB if i['id']==j['id']]

You could just use a simple filtering
b_ids = set(d["id"] for d in listB)
result = [d for d in listA if d["id"] in b_ids]
assuming that you would like to keep the dictionary from listA when a possibly different dictionary with the same "id" value is in listB.

Related

How to update my list of dictionary with nested for loops? [duplicate]

This question already has answers here:
How do I iterate through two lists in parallel?
(8 answers)
Closed 2 years ago.
Here I am trying to update the the list of dictionary like this but I am not getting the desired output. How can I solve this ?
def get_values(self):
list1 = [{'key1': 'value1'}, {'key2': 'value2'}]
list2 = [100, 200]
for i in list1:
for j in list2:
i['val']=j
return list1
The current output is
[{"key1": "value1","val": 200},{"key2": "value2","val": 200}],
The output I want is:
[{"key1": "value1","val": 100},{"key2": "value2","val": 200}],
You can write a list comprehension using zip() to achieve this. Below are few alternatives to achieve this in different Python versions.
In Python 3.9.0+, using |:
>>> list1 = [{'key1': 'value1'}, {'key2': 'value2'}]
>>> list2 = [100, 200]
>>> [l1 | {'val': v} for l1, v in zip(list1, list2)]
[{'key1': 'value1', 'val': 100}, {'key2': 'value2', 'val': 200}]
In Python 3.5+ using **
>>> [{**l1, 'val': v} for l1, v in zip(list1, list2)]
[{'key1': 'value1', 'val': 100}, {'key2': 'value2', 'val': 200}]
Issue with your code is that your are doing nested iteration of list list2 for both the values of list1, because of which 'val' is firstly getting set as 100 and then 200, and your dictionaries are preserving the last value of list2 i.e. 200. zip() will let you iterate both the iterables together by fetching element corresponding to same index from both the lists.
Hence, you code using explicit for loop could be written using zip() as:
list1 = [{'key1': 'value1'}, {'key2': 'value2'}]
list2 = [100, 200]
for i, j in zip(list1, list2):
i['val'] = j
You can do this also without zip
list1 = [{'key1': 'value1'}, {'key2': 'value2'}]
list2 = [100, 200]
for index, dictionary in enumerate(list1):
dictionary['val']=list2[index]
print(list1)
You need to iterate over both lists at the same time.
Python has a function zip useful for this. It pairs together each position in two (or more) sequences.
In this example we're using strings here as sequences of characters, just to be brief:
>>> list(zip('abc', '123'))
[('a', '1'), ('b', '2'), ('c', '3')]
So, you can fix your function:
def get_values(self):
list1 = [{'key1': 'value1'}, {'key2': 'value2'}]
list2 = [100, 200]
for d, n in zip(list1, list2):
d['val'] = n
return list1

How to make a dictionary from two nested list?

I have two nested lists:
list1 = [['s0'], ['s1'], ['s2']]
list2 = [['hello','world','the'],['as','per','the'],['assets','order']]
and I want to make a dictionary from these lists with keys from list1 and values from list2:
d = {s0:['hello','world','the'],s1:['as','per','the'],s2:['assets','order']}
The output should look like this:
d = {s0:['hello','world','the'],s1:['as','per','the'],s2:['assets','order']}
The following code works if list1 is a normal (non-nested) list. But it doesn't work when list1 is a nested list.
dict(zip(list1, list2))
The problem here is that lists are not hashable, so one thing you can do is to flatten your list with itertools.chain and then build the dictionary with strings (which are immutable) as keys following you're current approach (read here for a more detailed explanation on this topic):
from itertools import chain
dict(zip(chain.from_iterable(list1),list2))
{'s0': ['hello', 'world', 'the'],
's1': ['as', 'per', 'the'],
's2': ['assets', 'order']}
If you want to do it manually (to understand algorithm for exemple), here is a way to do so:
list1 = [['s0'], ['s1'], ['s2']]
list2 = [['hello','world','the'],['as','per','the'],['assets','order']]
if len(list1) != len(list2):
exit(-1)
res = {}
for index, content in enumerate(list1):
res[content[0]] = list2[index]
print(res)
Another answer could be :
list1 = [['s0'], ['s1'], ['s2']]
list2 = [['hello','world','the'],['as','per','the'],['assets','order']]
output_dict = {element1[0]: element2 for element1, element2 in zip(list1, list2)}
An similar way of this dict-comprehension :
output_dict = {element1: element2 for [element1], element2 in zip(list1, list2)}
Output :
{'s0': ['hello', 'world', 'the'],
's1': ['as', 'per', 'the'],
's2': ['assets', 'order']}
It's a strange way to store matching information in the first place, but I would combine them like this:
list1 = [['s0'], ['s1'], ['s2']]
list2 = [['hello','world','the'],['as','per','the'],['assets','order']]
assert(len(list1) == len(list2))
output_dict = dict()
for index in range(len(list1)):
output_dict[list1[index][0] = list2[index]
result:
{'s0': ['hello', 'world', 'the'], 's1': ['as', 'per', 'the'], 's2': ['assets', 'order']}
I am assuming that the variables s0, s1 and s2 are meant to be strings like in the first list.

How to combine dictionaries within an array based on the same key-value pairs?

For example in the below list, I'd like to combine all dictionaries that share the same 'id' and 'name.'
Input:
l = [{'id':'1','name':'a','key1':'1'},
{'id':'1','name':'a','key2':'3'},
{'id':'1','name':'a','key3':'4'},
{'id':'2','name':'a','key5':'1'},
{'id':'2','name':'a','key7':'c'},
{'id':'1','name':'b','key5':'1'}]
Desired Result:
l = [{'id':'1','name':'a','key1':'1','key2':'3','key3':'4'},
{'id':'2','name':'a','key5':'1','key7':'c'},
{'id':'1','name':'b','key5':'1'}]
If possible, I'd like the function to also take different number of arguments for which keys the dictionaries would have to share for them to combine. For example, if I just wanted to combine based on just the 'id' instead of the 'key' and the 'name,' the result would be different.
itertools.groupby does the grouping for you. All that's left to do then is to merge the list of iterables of dictionaries (grouped by id) into a list of dictionaries:
>>> import itertools
>>> l = [ dict(reduce(lambda a, b: a + b.items(), lst, [])) for lst in \
[ list(grouper) for key, grouper in \
itertools.groupby(l, lambda x: (x["id"], x["name"])) ] \
]
>>> l
[{'id': '1', 'key1': '1', 'key2': '3', 'key3': '4', 'name': 'a'},
{'id': '2', 'key5': '1', 'key7': 'c', 'name': 'a'},
{'id': '1', 'key5': '1', 'name': 'b'}]
That's clearly not the most readable version to do it; you should probably use a helper function that merges the dictionaries instead of the nested list comprehensions.
Traditional Way :D
result = []
for item in l :
check = False
# check item, is it exist in result yet (r_item)
for r_item in result :
if item['id'] == r_item['id'] and item['name'] == r_item['name'] :
# if found, add all key to r_item ( previous record)
check = True
r_item.update( item )
if check == False :
# if not found, add item to result (new record)
result.append( item )

Matching and Appending

I'm trying to figure out how to run 1 list through another list, and whenever the first names match, append it to the new list if it exists
list1 = [["Ryan","10"],["James","40"],["John","30"],["Jake","15"],["Adam","20"]]
list2 = [["Ryan","Canada"],["John","United States"],["Jake","Spain"]]
So it looks something like this.
list3 = [["Ryan","Canada","10"],["John","United States","30"],["Jake","Spain","15"]
So far I haven't really been able to even come close, so even the smallest guidance would be much appreciated. Thanks.
You could transform them into dictionaries and then use a list comprehension:
dic1 = dict(list1)
dic2 = dict(list2)
list3 = [[k,dic2[k],dic1[k]] for k in dic2 if k in dic1]
If ordering isn't a concern, the most straightforward way is to convert the lists into more suitable data structures: dictionaries.
ages = dict(list1)
countries = dict(list2)
That'll make it a cinch to combine the pieces of data:
>>> {name: [ages[name], countries[name]] for name in ages.keys() & countries.keys()}
{'Ryan': ['10', 'Canada'], 'Jake': ['15', 'Spain'], 'John': ['30', 'United States']}
Or even better, use nested dicts:
>>> {name: {'age': ages[name], 'country': countries[name]} for name in ages.keys() & countries.keys()}
{'Ryan': {'country': 'Canada', 'age': '10'},
'Jake': {'country': 'Spain', 'age': '15'},
'John': {'country': 'United States', 'age': '30'}}
If the names are unique you can make list1 into a dictionary and then loop through list2 adding items from this dictionary.
list1 = [["Ryan","10"],["James","40"],["John","30"],["Jake","15"],["Adam","20"]]
list2 = [["Ryan","Canada"],["John","United States"],["Jake","Spain"]]
list1_dict = dict(list1)
output = [item + [list1_dict[item[0]]] for item in list2]
If not, then you need to decide how to deal with cases of duplicate names.
You can use a set and an OrderedDict to combine the common names and keep order:
list1 = [["Ryan","10"],["James","40"],["John","30"],["Jake","15"],["Adam","20"]]
list2 = [["Ryan","Canada"],["John","United States"],["Jake","Spain"]]
from collections import OrderedDict
# get set of names from list2
names = set(name for name,_ in list2)
# create an OrderedDict using name as key and full sublist as value
# filtering out names that are not also in list2
d = OrderedDict((sub[0], sub) for sub in list1 if sub[0] in names)
for name, country in list2:
if name in d:
# add country from each sublist with common name
d[name].append(country)
print(d.values()) # list(d.values()) for python3
[['Ryan', '10', 'Canada'], ['John', '30', 'United States'], ['Jake', '15', 'Spain']]
If list2 always has common names you can remove the if name in d:

how to get python list from other list which has dict as elements

i have a list, i want get key=value in other list
for example:
my_list = [
{'Key': 'Apple', 'Value': 'Fruit'},
{'Key': 'Car', 'Value': 'Automobile'},
{'Key': 'Dog', 'Value': 'Animal'},
{'Key': 'Bolt', 'Value': 'Runner'}]
I have a my_list, i want to get output as:
new_list = ['Apple=Fruit', 'Car=Automobile', 'Dog=Animal', 'Bolt=Runner']
Using a list comprehension with join
>>> my_list=[{'Key':'Apple','Value':'Fruit'},
{'Key':'Car','Value':'Automobile'},
{'Key':'Dog','Value':'Animal'},
{'Key':'Bolt','Value':'Runner'}]
>>> new_list = ['='.join([i['Key'], i['Value']]) for i in my_list]
>>> new_list
['Apple=Fruit', 'Car=Automobile', 'Dog=Animal', 'Bolt=Runner']
I am a bit confused by your naming though. With the names 'Key' and 'Value' are you actually intending to make a dict? As your expected output is written (and my above code produces) it is a list of concatenated strings.
If you do indeed want to make a dict out of these, you can do something similar
my_list=[{'Key':'Apple','Value':'Fruit'},
{'Key':'Car','Value':'Automobile'},
{'Key':'Dog','Value':'Animal'},
{'Key':'Bolt','Value':'Runner'}]
>>> new_dict = {i['Key'] : i['Value'] for i in my_list}
>>> new_dict
{'Car': 'Automobile', 'Bolt': 'Runner', 'Apple': 'Fruit', 'Dog': 'Animal'}
Alternative implementation, using map and str.format:
>>> my_list=[{'Key': 'Apple', 'Value': 'Fruit'},
{'Key': 'Car', 'Value': 'Automobile'},
{'Key': 'Dog', 'Value': 'Animal'},
{'Key': 'Bolt', 'Value': 'Runner'}]
>>> map(lambda d: "{Key}={Value}".format(**d), my_list)
['Apple=Fruit', 'Car=Automobile', 'Dog=Animal', 'Bolt=Runner']
Or (likely to be considerably more use in the long run):
>>> {d['Key']: d['Value'] for d in my_list}
{'Car': 'Automobile', 'Bolt': 'Runner', 'Apple': 'Fruit', 'Dog': 'Animal'}
Using str.format and accessing each dict's values
["{}={}".format(d.values()[1],d.values()[0]) for d in my_list]
['Apple=Fruit', 'Car=Automobile', 'Dog=Animal', 'Bolt=Runner']
Or using the keys:
["{}={}".format(d["Key"],d["Value"]) for d in my_list]

Categories

Resources