Can we use Intersection and Union in 2 Python dictionaries?

5 mins read
Can we use Intersection, union in 2 python dictionary?

In this article, we’re going perform logical operations on two Python Dictionaries. The most straightforward ways to find the intersection, union, difference, and symmetric difference of two dictionaries in Python, both at the level of only keys and key-value pairs.

Perform Logical Operations on Two Python Dictionaries.

Let’s consider 2 dictionaries that have:

  • values of int type (so as we can use also mathematical operations),
  • some keys in common,
  • some key-value pairs in common,
  • other key-value pairs are specific for each dictionary.
d1 = {'a':1, 'b':2, 'c':3, 'd':4, 'e':5, 'f':6}
d2 = {'c':3, 'd':4, 'e':50, 'f':60, 'g':7, 'h':8}

The aim here is to create a new dictionary for each of the following logical operations:

Intersection (“and”):

  • the same key-value pairs in both dictionaries,
  • the same keys in both dictionaries, with some rules applied to their corresponding values, in case the values of some keys are different in both dictionaries;

Union (“or”):

  • with some rules applied to the values of the keys in common, in case they are different in both dictionaries;

Difference (“not”):

  • taking the key-value pairs present in one of the dictionaries and absent in another (even if the same keys can be present in another dictionary with different values),
  • taking only the keys present in one of the dictionaries with their corresponding values;

Symmetric difference:

  • Taking only the keys present in any of the dictionaries and absent in another, with their corresponding values.

Intersection

To find the intersection of the dictionaries’ items (i.e. key-value pairs in common), we can use this short code:

inter = dict(d1.items() & d2.items())
inter
Output:
{'d': 4, 'c': 3}

What if we’re interested in finding all the keys in common, even if the values of some of them are different in our dictionaries? We can decide to keep the values of such keys from one dictionary, say, from d1:

inter_d1 = {k:v for k,v in d1.items() if k in d2}
inter_d1
Output:
{'c': 3, 'd': 4, 'e': 5, 'f': 6}

Or from d2:

inter_d2 = {k:v for k,v in d2.items() if k in d1}
inter_d2
Output:
{'c': 3, 'd': 4, 'e': 50, 'f': 60}

Alternatively, we might want to take both values for each of the keys in common from both dictionaries, apply a function to them, and use the result as a value for that key in the new dictionary:

inter_max = {k:max(d1[k],d2[k]) for k in d1.keys() if k in d2}
inter_min = {k:min(d1[k],d2[k]) for k in d1.keys() if k in d2}
inter_sum = {k:d1[k]+d2[k] for k in d1.keys() if k in d2}print(inter_max)
print(inter_min)
print(inter_sum)
Output:
{'c': 3, 'd': 4, 'e': 50, 'f': 60}
{'c': 3, 'd': 4, 'e': 5, 'f': 6}
{'c': 6, 'd': 8, 'e': 55, 'f': 66}

Of course, we can use any user-defined function for these purposes:

def extraction_twice(a,b):
    return (a-b)*2inter_extraction_twice = {k:extraction_twice(d2[k],d1[k]) for k in d1.keys() if k in d2}
inter_extraction_twice
Output:
{'c': 0, 'd': 0, 'e': 90, 'f': 108}

Also in the case when the values are of string type:

d1_new = {1:'my', 2:'our', 3:'your'}
d2_new = {1:'home', 2:'family', 4:'work'}def combine_strings(str1,str2):
    return str1+ ' '+ str2inter_string = {k:combine_strings(d1_new[k],d2_new[k]) for k in d1_new.keys() if k in d2_new}
inter_string
Output:
{1: 'my home', 2: 'our family'}

Union

The code for merging two dictionaries is similar to the one we used for finding the intersection of the dictionaries’ key-value pairs, only that here we should use the merge operator:

union = dict(d1.items()|d2.items())
union
Output:
{'d': 4, 'c': 3, 'h': 8, 'f': 60, 'a': 1, 'e': 50, 'g': 7, 'b': 2}

Side note: in Python 3.9, this piece of code is simplified to d1|d2.

The issue here is that the value for the key c was taken from d2, while for d — from d1. To be sure from where exactly the values are taken for the keys in common, there is a better option — the unpacking operator **:

union_d1 = {**d2, **d1}
union_d1
Output:
{'c': 3, 'd': 4, 'e': 5, 'f': 6, 'g': 7, 'h': 8, 'a': 1, 'b': 2}

Here all the values for the keys in common were taken from d1. To take them from d2, we have to mirror the code:

union_d2 = {**d1, **d2}
union_d2
Output:
{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 50, 'f': 60, 'g': 7, 'h': 8}

As earlier, instead of taking the values for the keys in common directly from one of the dictionaries, we might want to take both values for each such key from both dictionaries, apply a function to them (standard or user-defined), and use the result as a value for that key in the new dictionary. The approach here includes:

  • creating a copy of one of the dictionaries,
  • updating this copy based on the function to apply and on the values from another dictionary,
  • merging the updated copy with another dictionary.
d1_copy = d1.copy()
d1_copy.update({k:max(d1[k],d2[k]) for k in d2 if d1.get(k)})
union_max = {**d2, **d1_copy}
union_max
Output:
{'c': 3, 'd': 4, 'e': 50, 'f': 60, 'g': 7, 'h': 8, 'a': 1, 'b': 2}

In this case, we used the max() function. However, we could use any other standard or user defined function, as we did earlier for finding the intersection.

Difference

To isolate items unique to one of the dictionaries (even if the same keys can be present in another dictionary with different values), for example, d1, we can use one of the two pieces of code below:

dif_d1 = dict(d1.items() - d2.items())
dif_d1
Output:
{'f': 6, 'a': 1, 'e': 5, 'b': 2}

or:

dif_d1 = {k:v for k,v in d1.items() if k not in d2 or d2[k]!=v}
dif_d1
Output:
{'a': 1, 'b': 2, 'e': 5, 'f': 6}

For d2, the code must be mirrored:

dif_d2 = dict(d2.items() - d1.items())
dif_d2
Output:
{'h': 8, 'f': 60, 'e': 50, 'g': 7}

or:

dif_d2 = {k:v for k,v in d2.items() if k not in d1 or d1[k]!=v}
dif_d2
Output:
{'e': 50, 'f': 60, 'g': 7, 'h': 8}

If we want to isolate the keys unique to one of the dictionaries with their corresponding values, for example, d1, we should use the following dictionary comprehension:

dif_d1_keys={k:v for k,v in d1.items() if k not in d2}
dif_d1_keys
Output:
{'a': 1, 'b': 2}

For d2:

dif_d2_keys={k:v for k,v in d2.items() if k not in d1}
dif_d2_keys
Output:
{'g': 7, 'h': 8}

Symmetric Difference

Finally, to find the symmetric difference, i.e. the keys unique to both dictionaries with their corresponding values, we need:

  • to find the differences for both dictionaries according to the last formula,
  • to unite the resulting dictionaries in one.
sym_dif = {**{k:v for k,v in d1.items() if k not in d2}, **{k:v for k,v in d2.items() if k not in d1}}
sym_dif
Output:
{'a': 1, 'b': 2, 'g': 7, 'h': 8}

10 uses of dictionary

Here are 10 uses of dictionary in python:

Lookup: A dictionary is a key-value store. It allows for quick lookup of values associated with a given key.

# Lookup example
my_dict = {"apple": 2.99, "banana": 1.99, "orange": 0.99}
price_of_apple = my_dict["apple"]
print(price_of_apple) # Output: 2.99

Counting: Dictionaries can be used to count occurrences of items in a list or other iterable data types.

# Counting example
my_list = [1, 2, 3, 1, 2, 1, 3, 4, 5]
my_dict = {}
for item in my_list:
    if item in my_dict:
        my_dict[item] += 1
    else:
        my_dict[item] = 1
print(my_dict) # Output: {1: 3, 2: 2, 3: 2, 4: 1, 5: 1}

Grouping: Dictionaries can be used to group items together based on specific criteria.

# Grouping example
my_list = ["apple", "banana", "apricot", "orange", "avocado"]
my_dict = {}
for item in my_list:
    if item[0] in my_dict:
        my_dict[item[0]].append(item)
    else:
        my_dict[item[0]] = [item]
print(my_dict) # Output: {'a': ['apple', 'apricot', 'avocado'], 'b': ['banana'], 'o': ['orange']}

Data Mapping: Dictionaries are commonly used for mapping values between different data types or systems.

# Data Mapping example
my_dict = {"True": True, "False": False, "Yes": True, "No": False}
value = my_dict["Yes"]
print(value) # Output: True

Configuration: Dictionaries can be used to store configuration settings for a program or application.

# Configuration example
config = {
    "api_key": "my_api_key",
    "base_url": "https://api.example.com",
    "max_retries": 3
}

Memoization: Memoization is a technique used to speed up computations by caching previously computed values. Dictionaries can be used to implement memoization.

# Memoization example
my_dict = {}
def fibonacci(n):
    if n in my_dict:
        return my_dict[n]
    if n <= 2:
        return 1
    result = fibonacci(n-1) + fibonacci(n-2)
    my_dict[n] = result
    return result
print(fibonacci(10)) # Output: 55

Sparse Matrices: Dictionaries can be used to represent sparse matrices (matrices with mostly zero values) in a memory-efficient manner.

# Sparse Matrices example
my_matrix = {(0, 0): 1, (1, 2): 3, (2, 1): 4}

Caching: Dictionaries can be used as a cache for frequently accessed data, allowing for faster access and reduced computation time.

# Caching example
import functools
@functools.lru_cache(maxsize=128)
def fibonacci(n):
    if n <= 2:
        return 1
    return fibonacci(n-1) + fibonacci(n-2)

Serialization: Dictionaries can be serialized and deserialized to and from various formats (such as JSON or YAML) for storage or transmission.

# Serialization example
import json
my_dict = {"apple": 2.99, "banana": 1.99, "orange": 0.99}
json_string = json.dumps(my_dict)
print(json_string) # Output: {"apple": 2.99, "banana": 1.99, "orange": 0.99}

Querying: Dictionaries can be queried to filter or extract specific data based on criteria or conditions.

# Querying example
my_list = [
{"name": "Alice", "age": 30}, 
{"name": "Bob", "age": 25}, 
{"name": "Charlie", "age": 35}
]
result = [item for item in my_list if item["age"] > 30]

# Output: [{'name': 'Charlie', 'age': 35}]

Conclusion

To wrap up, we considered fast and comprehensive ways to perform the main logical operations on two dictionaries in Python for creating a new one. We found the intersection, union, difference, and symmetric difference of our two dictionaries both at the level of only keys and key-value pairs, sometimes using various functions for the keys in common. Certainly, these approaches are not the only ones, and you can come up with other ideas, or maybe in future versions of Python, there will be introduced more explicit ways for these tasks. However, the pieces of code suggested are concise and elegant, and almost all of them are one-liners.

Back

This content is created from Medium

Dharmendra is a blogger, author, Expert in IT Services and admin of DJTechnews. Good experience in software development. Love to write articles to share knowledge and experience with others. He has deep knowledge of multiple technologies and is always ready to explore new research and developments.

Leave a Comment

Stay Connected with us