Python lookup key/Values between list of dictionaries - python

I am trying to lookup two list of dictionaries based on matching keys. If the keys and values match between any dictionaries, I want to copy key value pairs from second dictionary to the first one and return it as an output. But if no match is found, the dictionary should be returned as reject. Below is an example of what I want to do and what I have coded. I am able to get my results but I want to know if there is a better way to do this.
input_list = [{'a':1, 'b': 2, 'c':3},
{'a':4, 'b': 5, 'c':6},
{'a':7, 'b': 8, 'c':9}]
ref_list = [{'a':1, 'b': 2, 'd':3, 'e': 10},
{'a':4, 'b': 5, 'd':6, 'e': 11}]
matching_cols = ['a','b']
copy_over_cols = ['d','e']
expected_output_list = [{'a':1, 'b': 2, 'c':3, 'd':3, 'e':10,},
{'a':4, 'b': 5, 'c':6, 'd':6, 'e':11,}]
expected_reject_list = [{'a':7, 'b': 8, 'c':9}]
#What I have coded so far
def lookup_dict(input_list,ref_list,matching_cols,copy_over_cols):
output_list = []
reject_list = []
for input_dict in input_list:
match_cols_dict = dict(tuple((col,input_dict[col]) for col in matching_cols))
matched = False
copy_over_items = {}
for ref_dict in ref_list:
check_cols_dict = dict(tuple((col,ref_dict[col]) for col in matching_cols))
if match_cols_dict == check_cols_dict:
matched = True
copy_over_items = dict((tuple((col,ref_dict[col]) for col in copy_over_cols)))
break
if matched == True:
input_dict.update(copy_over_items)
output_list.append(input_dict)
else:
reject_list.append(input_dict)
return output_list, reject_list
output_list, reject_list = lookup_dict(input_list,ref_list,matching_cols,copy_over_cols)
print("output - ", output_list, "reject - ", reject_list)
Your help is greatly appreciated. :)

Try this:
output_list = list()
reject_list = list()
for i in input_list:
matches = [d for d in ref_list if all(i[c]==d[c] for c in matching_cols)]
if len(matches)>0:
j = matches[0]
output_list.append({**i, **{k: j[k] for k in copy_over_cols}})
else:
reject_list.append(i)
>>> output_list
[{'a': 1, 'b': 2, 'c': 3, 'd': 3, 'e': 10},
{'a': 4, 'b': 5, 'c': 6, 'd': 6, 'e': 11}]
>>> reject_list
[{'a': 7, 'b': 8, 'c': 9}]

Related

How to append column when compared columns are equal

I have two lists that I need to merge based on a column name that exists in both. The source is JSON.
I'm not sure how to do this, I looked at How to merge multiple dicts with same key? but that one doesn't constrain anything.
Example:
dict1 = {"a": 3, 'b': 4}
dict2 = {"a": 3, 'c': 5}
dict3 = {"a": 1, 'b': 2}
dict4 = {"a": 1, 'c': 8}
dict_result = [{"a": 3, 'b': 4, 'c': 5},{"a": 1, 'b': 2, 'c': 8}]
BR
Here try this.
dict1 = {"a": 3, 'b': 4}
dict2 = {"a": 3, 'c': 5}
dict3 = {"a": 1, 'b': 2}
dict4 = {"a": 1, 'c': 8}
def merge_dictionary(*args):
dictionary = []
dict_result=[]
app_index = 0 # append index
for dic in (args):
for item, value in dic.items():
if [item, value] not in dictionary:
dictionary.append([item, value])
for index, x in enumerate(dictionary):
if index%3==0:
dict_result.append({x[0]:x[1]})
app_index = index
else:
dict_result[app_index//3].update({x[0]:x[1]})
return dict_result
print(merge_dictionary(dict1, dict2, dict3, dict4))

Finding all the dicts of max len in a list of dicts

I have a list of dictionaries
ld = [{'a': 1}, {'b': 2, 'c': 3}, {'d': 4, 'e': 5}]
I need to get all the elements with the longest length from my list, i.e.
{'b': 2, 'c': 3} and {'d': 4, 'e': 5}.
I'm not very knowledgeable in Python but I found that:
>>> max(ld, key=len)
{'b': 2, 'c': 3}
And, an even better solution that returns the index of the longest length dictionary:
>>> max(enumerate(ld), key=lambda tup: len(tup[1]))
(1, {'b': 2, 'c': 3})
I would like to use an expression that would return something like
(1: {'b': 2, 'c': 3}, 2: {'d': 4, 'e': 5})
and I feel like I'm not far from the solution (or maybe I am) but I just don't know how to get it.
You can find the length of the maximum dictionary in the structure, and then use a list comprehension:
ld = [{'a':1}, {'b':2, 'c':3}, {'d':4, 'e':5}]
_max = max(map(len, ld))
new_result = dict(i for i in enumerate(ld) if len(i[-1]) == _max)
Output:
{1: {'b': 2, 'c': 3}, 2: {'d': 4, 'e': 5}}
Ajax1234 provided a really good solution. If you want something of a beginner level, here's a solution.
ld = [{'a':1}, {'b':2, 'c':3}, {'d':4, 'e':5}]
ans = dict()
for value in ld:
if len(value) in ans:
ans[len(value)].append(value)
else:
ans[len(value)] = list()
ans[len(value)].append(value)
ans[max(ans)]
Basically, you add everything in a dictionary to get the maximum dictionary size to be the key, and dictionary list to be the value, and then get that maximum size list of dictionaries.
There are a number of ways you could do this in python. Here's one example which illustrates a few different python capabilities:
ld = [{'a':1}, {'b':2, 'c':3}, {'d':4, 'e':5}]
lengths = list(map(len, ld)) # [1, 2, 2]
max_len = max(lengths) # 2
index_to_max_length_dictionaries = {
index: dictionary
for index, dictionary in enumerate(ld)
if len(dictionary) == max_len
}
# output: {1: {'b': 2, 'c': 3}, 2: {'d': 4, 'e': 5}}
Find the maximum length and then use a dictionary comprehension to find the dictionaries with such length
max_l = len(max(ld, key=len))
result = {i: d for i, d in enumerate(ld) if len(d) == max_l}
This is the simplest and more readable approach you can take
Below is another path, a better (but more verbose) approach
max_length = 0
result = dict()
for i, d in enumerate(ld):
l = len(d)
if l == max_length:
result[i] = d
elif l > max_length:
max_length = l
result = {i: d}
This is the most efficient approach. It just iterate 1 time through the full input list

Add values from two dictionaries

dict1 = {a: 5, b: 7}
dict2 = {a: 3, c: 1}
result {a:8, b:7, c:1}
How can I get the result?
this is a one-liner that would do just that:
dict1 = {'a': 5, 'b': 7}
dict2 = {'a': 3, 'c': 1}
result = {key: dict1.get(key, 0) + dict2.get(key, 0)
for key in set(dict1) | set(dict2)}
# {'c': 1, 'b': 7, 'a': 8}
note that set(dict1) | set(dict2) is the set of the keys of both your dictionaries. and dict1.get(key, 0) returns dict1[key] if the key exists, 0 otherwise.
this works on a more recent python version:
{k: dict1.get(k, 0) + dict2.get(k, 0) for k in dict1.keys() | dict2.keys()}
You can use collections.Counter which implements addition + that way:
>>> from collections import Counter
>>> dict1 = Counter({'a': 5, 'b': 7})
>>> dict2 = Counter({'a': 3, 'c': 1})
>>> dict1 + dict2
Counter({'a': 8, 'b': 7, 'c': 1})
if you really want the result as dict you can cast it back afterwards:
>>> dict(dict1 + dict2)
{'a': 8, 'b': 7, 'c': 1}
Here is a nice function for you:
def merge_dictionaries(dict1, dict2):
merged_dictionary = {}
for key in dict1:
if key in dict2:
new_value = dict1[key] + dict2[key]
else:
new_value = dict1[key]
merged_dictionary[key] = new_value
for key in dict2:
if key not in merged_dictionary:
merged_dictionary[key] = dict2[key]
return merged_dictionary
by writing:
dict1 = {'a': 5, 'b': 7}
dict2 = {'a': 3, 'c': 1}
result = merge_dictionaries(dict1, dict2)
result will be:
{'a': 8, 'b': 7, 'c': 1}
A quick dictionary comprehension that should work on any classes which accept the + operator. Performance might not be optimal.
{
**dict1,
**{ k:(dict1[k]+v if k in dict1 else v)
for k,v in dict2.items() }
}
Here is another approach but it is quite lengthy!
d1 = {'a': 5, 'b': 7}
d2 = {'a': 3, 'c': 1}
d={}
for i,j in d1.items():
for k,l in d2.items():
if i==k:
c={i:j+l}
d.update(c)
for i,j in d1.items():
if i not in d:
d.update({i:j})
for m,n in d2.items():
if m not in d:
d.update({m:n})
Think it's much simpler.
a={'a':3, 'b':5}
b= {'a':4, 'b':7}
{i:a[i]+b[i] for i in a.keys()}
Output: {'a': 7, 'b': 12}

How to access indexes of a list of dictionaries?

Suppose I am give a list of dictionaries, where
dict1 = dict(a = 2, b = 5, c = 7)
dict2 = dict(c = 5, d = 5, e = 1)
dict3 = dict(e = 2, f = 4, g = 10)
list_of_dictionaries = [dict1, dict2, dict3]
How would I be able to, find the value of the highest index (aka the latest dictionary)?
So if I were to write a method to delete an item from the list of dictionaries, let's say I want to delete c from the dictionary.
How would I be able to delete the c from the second dictionary instead of the first?
The key is reversing through the list with reverse indexing (a_list[::-1]).
From there once you find any dictionary that matches the requirements alter it and quit the function or loop - hence the early returns.
This code:
def get_last(bucket,key):
for d in bucket[::-1]:
if key in d.keys():
return d[key]
return None
def set_last(bucket,key,val):
for d in bucket[::-1]:
if key in d.keys():
d[key] = val
return
def pop_last(bucket,key):
out = None
for d in bucket[::-1]:
if key in d.keys():
return d.pop(key)
dict1 = {'a': 2, 'b': 5, 'c': 7}
dict2 = {'c': 5, 'd': 5, 'e': 1}
dict3 = {'e': 2, 'f': 4, 'g': 10}
list_of_dictionaries = [dict1, dict2, dict3]
print get_last(list_of_dictionaries ,'c')
set_last(list_of_dictionaries ,'c',7)
print list_of_dictionaries
popped = pop_last(list_of_dictionaries ,'c')
print popped
print list_of_dictionaries
Gives:
5
[{'a': 2, 'c': 7, 'b': 5}, {'c': 7, 'e': 1, 'd': 5}, {'e': 2, 'g': 10, 'f': 4}]
7
[{'a': 2, 'c': 7, 'b': 5}, {'e': 1, 'd': 5}, {'e': 2, 'g': 10, 'f': 4}]
I am not exactly sure what you mean but I wan to show you a couple of things that might help:
First here is how your dictionaries should look like:
dict1 = {"a" :2, "b" : 5, "c" :7}
dict2 = {"c" :5, "d" :5, "e" :1}
dict3 = {"e" :2, "f" :4, "g" :10}
Then you asked this: "How would I be able to delete the c from the second dictionary instead of the first?"
You can do delete it this way:
del dict2["c"]

Python - Find non mutual items in two dicts

Lets say I have two dictionaries:
a = {'a': 1, 'b': 2, 'c': 3}
b = {'b': 2, 'c': 3, 'd': 4, 'e': 5}
What's the most pythonic way to find the non mutual items between the two of them such that for a and b I would get:
{'a': 1, 'd': 4, 'e': 5}
I had thought:
{key: b[key] for key in b if not a.get(key)}
but that only goes one way (b items not in a) and
a_only = {key: a[key] for key in a if not b.get(key)}.items()
b_only = {key: b[key] for key in b if not a.get(key)}.items()
dict(a_only + b_only)
seams very messy. Any other solutions?
>>> dict(set(a.iteritems()) ^ set(b.iteritems()))
{'a': 1, 'e': 5, 'd': 4}
Try with the symetric difference of set() :
out = {}
for key in set(a.keys()) ^ set(b.keys()):
out[key] = a.get(key, b.get(key))
diff = {key: a[key] for key in a if key not in b}
diff.update((key,b[key]) for key in b if key not in a)
just a bit cheaper version of what you have.
>>> a = {'a': 1, 'b': 2, 'c': 3}
>>> b = {'b': 2, 'c': 3, 'd': 4, 'e': 5}
>>> keys = set(a.keys()).symmetric_difference(set(b.keys()))
>>> result = {}
>>> for k in keys: result[k] = a.get(k, b.get(k))
...
>>> result
{'a': 1, 'e': 5, 'd': 4}
Whether this is less messy than your version is debatable, but at least it doesn't re-implement symmetric_difference.

Categories

Resources