# 5 Best Ways to Check If Array Pairs Are Divisible by k in Python

Rate this post

π‘ Problem Formulation: We need a program to determine whether pairs of elements from a given array can be evenly divided by a specified integer `k`. For instance, if the input array is `[2, 4, 6, 8]` and `k` is `4`, the pair (4, 8) is divisible by `k`, but (2, 6) is not. We want to verify divisibility for all unique pairs in the array.

## Method 1: Brute Force Approach

This method involves iterating over each unique pair in the array and checking whether their sum is divisible by `k`. It is straightforward but not very efficient for large arrays because its time complexity is `O(n^2)`.

Here’s an example:

```def are_pairs_divisible_by_k(arr, k):
for i in range(len(arr)):
for j in range(i+1, len(arr)):
if (arr[i] + arr[j]) % k != 0:
return False
return True

print(are_pairs_divisible_by_k([2, 4, 6, 8], 4))```

Output: `True`

The function `are_pairs_divisible_by_k()` checks each unique pair by using two nested loops. If any pair’s sum is not divisible by `k`, it returns `False`; otherwise, it returns `True`.

## Method 2: Using Hashing

Hashing can be used to improve the efficiency by storing the frequency of remainders when the array elements are divided by `k`. The time complexity is reduced to `O(n)`, which is much better for large datasets.

Here’s an example:

```def are_pairs_divisible_by_k_hashing(arr, k):
remainder_freq = [0] * k

for num in arr:
remainder_freq[num % k] += 1

for i in range(1, (k+1)//2):
if remainder_freq[i] != remainder_freq[k - i]:
return False
return remainder_freq[0] % 2 == 0

print(are_pairs_divisible_by_k_hashing([2, 4, 6, 8], 4))```

Output: `True`

The function `are_pairs_divisible_by_k_hashing()` utilizes a list to store the frequencies of the moduli, and then compares pairs of these frequencies to make sure they can be paired off properly, indicating divisibility by `k`.

## Method 3: Using a Dictionary

Like the hashing method, we can use a Python dictionary to store and compare frequencies of remainders. It is similar in efficiency to Method 2 but can be easier to understand and implement.

Here’s an example:

```from collections import defaultdict

def are_pairs_divisible_by_k_dict(arr, k):
remainder_dict = defaultdict(int)

for num in arr:
remainder_dict[num % k] += 1

for i in range(1, (k+1)//2):
if remainder_dict[i] != remainder_dict[k - i]:
return False
return remainder_dict[0] % 2 == 0

print(are_pairs_divisible_by_k_dict([2, 4, 6, 8], 4))```

Output: `True`

The function `are_pairs_divisible_by_k_dict()` follows the same logic as the hashing approach but uses a dictionary, which allows cleaner syntax and potentially more flexibility in Python.

## Method 4: Using Combinations from itertools

This method uses the `itertools.combinations()` function to generate all unique pairs and then checks their divisibility. This method is more Pythonic and easier to read but does not offer performance improvements over the brute force approach.

Here’s an example:

```from itertools import combinations

def are_pairs_divisible_by_k_combinations(arr, k):
for pair in combinations(arr, 2):
if sum(pair) % k != 0:
return False
return True

print(are_pairs_divisible_by_k_combinations([2, 4, 6, 8], 4))```

Output: `True`

The function `are_pairs_divisible_by_k_combinations()` utilizes the combinations generator from itertools to iterate over pairs without writing nested loops, keeping the code compact and readable.

## Bonus One-Liner Method 5: Using all() and itertools

A one-liner version using `all()` to check the divisibility for all pairs in a functional programming style. However, remember that readability may be compromised.

Here’s an example:

```from itertools import combinations

are_pairs_divisible_by_k_one_liner = lambda arr, k: all((sum(pair) % k == 0) for pair in combinations(arr, 2))
print(are_pairs_divisible_by_k_one_liner([2, 4, 6, 8], 4))```

Output: `True`

This one-liner defines a lambda function that uses `all()` and `combinations()` to check divisibility for all pairs. It’s a compact solution but may not be as clear as the more verbose methods.

## Summary/Discussion

• Method 1: Brute Force. Simple to understand. Inefficient for larger datasets due to O(n^2) time complexity.
• Method 2: Using Hashing. Much more efficient with O(n) time complexity. Requires understanding of modulo arithmetic and how to use an array to store frequencies.
• Method 3: Using a Dictionary. Equivalent to hashing in efficiency but possibly more readable. Makes use of Python’s powerful dictionary data structure.
• Method 4: Using itertools Combinations. Pythonic and readable. Performs similarly to the brute force method in terms of computational complexity.
• Method 5: One-Liner using all() and itertools. Compact and efficient but may be harder to understand. Not recommended for complex logic or beginners.