I made some improvements based on vallentin's answer, mainly using copy.deepcopy
to prevent any changes to the input.
Note that using sorted()
or .copy()
is insufficient, as sub-elements get changed when any merge happens.
I also added a .sort()
call on each interval to handle unsorted input, as well as a more explicit initial sort call for clarity.
Code:
import copy
def mergeIntervals(input_array, preserve_input=True):
'''
Python3 program for merging overlapping intervals.
If preserve_input is False, the input_array can be modified! Not just sorted, but even sub-elements can change!
See:
https://www.educative.io/answers/what-is-the-merge-overlapping-intervals-problem
https://www.geeksforgeeks.org/merging-intervals/
https://stackoverflow.com/questions/43600878/merging-overlapping-intervals
'''
if preserve_input:
intervals = copy.deepcopy(input_array)
else:
intervals = input_array
# Sort the given list of time intervals in ascending order of starting time.
intervals.sort(key=lambda interval: interval[0])
intervals[0].sort() # deal with unsorted input
# Create a stack with the first interval
merged = [intervals[0]]
for current in intervals[1:]:
current.sort() # deal with unsorted input
previous = merged[-1]
# Check for overlapping interval
if current[0] <= previous[-1]: # If it’s overlapping, then merge them into one interval;
previous[-1] = max(previous[-1], current[-1])
else: # otherwise, push it in the stack.
merged.append(current)
return merged
##### Testing code:
A_list = []
# Example from original question:
input_array = [[-25, -14], [-21, -16], [-20, -15], [-10, -7], [-8, -5], [-6, -3], [2, 4], [2, 3], [3, 6], [12, 15], [13, 18], [14, 17], [22, 27], [25, 30], [26, 29]]
A_list.append(input_array)
# Example with unsorted elements and sub-elements:
input_array = [[4, 2], [3, 1]]
A_list.append(input_array)
for preserve_input in [False, True]:
print(f'==> preserve_input = {preserve_input}')
for idx, a in enumerate(A_list):
print('------> idx = ', idx)
input_array = copy.deepcopy(a)
print('input before:', input_array)
output_array = mergeIntervals(input_array, preserve_input=preserve_input)
print('input after:', input_array)
print('output', output_array)
if input_array != a:
print('Input modified!')
if preserve_input:
raise
else:
print('No change in input.')
Output:
Note in particular the change of [22, 27]
to [22, 30]
in the first example, near the end.
==> preserve_input = False
------> idx = 0
input before: [[-25, -14], [-21, -16], [-20, -15], [-10, -7], [-8, -5], [-6, -3], [2, 4], [2, 3], [3, 6], [12, 15], [13, 18], [14, 17], [22, 27], [25, 30], [26, 29]]
input after: [[-25, -14], [-21, -16], [-20, -15], [-10, -3], [-8, -5], [-6, -3], [2, 6], [2, 3], [3, 6], [12, 18], [13, 18], [14, 17], [22, 30], [25, 30], [26, 29]]
output [[-25, -14], [-10, -3], [2, 6], [12, 18], [22, 30]]
Input modified!
------> idx = 1
input before: [[4, 2], [3, 1]]
input after: [[1, 4], [2, 4]]
output [[1, 4]]
Input modified!
==> preserve_input = True
------> idx = 0
input before: [[-25, -14], [-21, -16], [-20, -15], [-10, -7], [-8, -5], [-6, -3], [2, 4], [2, 3], [3, 6], [12, 15], [13, 18], [14, 17], [22, 27], [25, 30], [26, 29]]
input after: [[-25, -14], [-21, -16], [-20, -15], [-10, -7], [-8, -5], [-6, -3], [2, 4], [2, 3], [3, 6], [12, 15], [13, 18], [14, 17], [22, 27], [25, 30], [26, 29]]
output [[-25, -14], [-10, -3], [2, 6], [12, 18], [22, 30]]
No change in input.
------> idx = 1
input before: [[4, 2], [3, 1]]
input after: [[4, 2], [3, 1]]
output [[1, 4]]
No change in input.