First thing we need to do is figure out how to split the list into partitions.
To get all of the ways we can split the list into k sections, we can start by determine all of the ways k numbers can add up to len(arr), where each number is greater than 1.
To do so we can take advantage of itertools.
def partition_index(a, k):
for indices in product(range(1, len(a)), repeat=k):
if sum(indices) == len(a):
yield indices
for s in partition_index([9, 1, 2, 3, 4], 3):
print(s)
(1, 1, 3)
(1, 2, 2)
(1, 3, 1)
(2, 1, 2)
(2, 2, 1)
(3, 1, 1)
Perfect! Now if we want to split our array based on these values, it'll be easier if we turn them into tuples for the start and end of where to split. For this we can use itertools again!
def partition_index(a, k):
for indices in product(range(1, len(a)), repeat=k):
if sum(indices) == len(a):
yield list(pairwise([0, *accumulate(indices)]))
[(0, 1), (1, 2), (2, 5)]
[(0, 1), (1, 3), (3, 5)]
[(0, 1), (1, 4), (4, 5)]
[(0, 2), (2, 3), (3, 5)]
[(0, 2), (2, 4), (4, 5)]
[(0, 3), (3, 4), (4, 5)]
Now that we have this grouping, creating a method to do the partition is pretty straight forward:
def partition(a, k):
for indices in partition_index(a, k):
yield [a[i:j] for i, j in indices]
[[9], [1], [2, 3, 4]]
[[9], [1, 2], [3, 4]]
[[9], [1, 2, 3], [4]]
[[9, 1], [2], [3, 4]]
[[9, 1], [2, 3], [4]]
[[9, 1, 2], [3], [4]]
And finally we can use this output to get your desired results.
def minimized_difference(a, k):
final_diff, final_result = None, None
for result in partition(a, k):
result_max = [max(r) * len(r) for r in result]
diff = max(result_max) - min(result_max)
if final_diff is None or diff < final_diff:
final_diff, final_result = diff, result
return final_result
print(minimized_difference([5, 6, 7, 8, 9, 1, 2, 3, 4], 3))
[[5, 6, 7], [8, 9], [1, 2, 3, 4]]
Final code with some refactoring and covering corner cases:
from itertools import pairwise, product, accumulate
from typing import TypeVar, Iterable, Optional
T = TypeVar('T')
def partition_index(size: int, k: int) -> Iterable[list[tuple[int, int]]]:
for indices in product(range(1, size - k + 2), repeat=k):
if sum(indices) == size:
yield list(pairwise([0, *accumulate(indices)]))
def partition(data: list[T], k: int) -> Iterable[list[list[T]]]:
if len(data) < k or k <= 0:
return
for indices in partition_index(len(data), k):
yield [data[i:j] for i, j in indices]
def evaluate_result(result: list[list[T]]) -> int:
result_max = [max(r) * len(r) for r in result]
return max(result_max) - min(result_max)
def minimized_difference(data: list[int], k: int) -> Optional[list[list[int]]]:
return min(partition(data, k), default=None, key=evaluate_result)
print(minimized_difference([5, 6, 7, 8, 9, 1, 2, 3, 4], 3))