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 the future versions of Python, there will be introduced more explicit ways for these tasks. However, the pieces of code suggested are concise, elegant, and almost all of them are one-liners.

This content is created from Medium