Python – Grouped Consecutive Range Indices of Elements
Last Updated :
15 Mar, 2023
Given List of elements, for list of tuples, where each represents the continuity of occurrence of each element.
Input : test_list = [1, 1, 5, 6, 5, 5]
Output : {1: [(0, 1)], 5: [(2, 2), (4, 5)], 6: [(3, 3)]}
Explanation : 5 present at 2nd idx and also in continuation in 4th and 5th index, and hence recorded range.
Input : test_list = [5, 5, 5, 5, 5, 5]
Output : {5: [(0, 5)]}
Explanation : Only 5 present, hence recorded.
Method 1: Using groupby() + defaultdict() + len() + loop
In this, we perform consecutive elements grouping using groupby(), defaultdict() is used to initialize the tuple list, The len() is used to get length of repetition.
Python3
from itertools import groupby
from collections import defaultdict
test_list = [ 1 , 1 , 5 , 6 , 5 , 5 , 6 , 6 , 6 , 1 , 5 , 5 ]
print ( "The original list : " + str (test_list))
idx = 0
res = defaultdict( list )
for key, sub in groupby(test_list):
ele = len ( list (sub))
res[key].append((idx, idx + ele - 1 ))
idx + = ele
print ( "The grouped dictionary : " + str ( dict (res)))
|
Output
The original list : [1, 1, 5, 6, 5, 5, 6, 6, 6, 1, 5, 5]
The grouped dictionary : {1: [(0, 1), (9, 9)], 5: [(2, 2), (4, 5), (10, 11)], 6: [(3, 3), (6, 8)]}
Time complexity: O(n), where n is the length of the input list.
Auxiliary space: O(k), where k is the number of unique elements in the input list.
Method 2: Using loop and dictionary
- Initialize an empty dictionary called res to store the grouped ranges.
- Initialize a variable i to keep track of the current position in the list.
- Start a while loop that will continue until the end of the list is reached.
- Get the current element in the list using test_list[i] and use it as the key for the dictionary.
- Initialize a variable start to store the starting index of the current group, which is the current value of i.
- Start another while loop that will continue as long as the current element in the list is equal to the key.
- Within the loop, increment i to move to the next element in the list.
- When the loop ends, i-1 is the end index of the current group.
- Append a tuple of (start, end) to the list for the current key in the dictionary using res.setdefault(key, []).append((start, end)).
- Repeat the loop from step 4 until the end of the list is reached.
- Print the resulting dictionary of grouped ranges.
Python3
test_list = [ 1 , 1 , 5 , 6 , 5 , 5 , 6 , 6 , 6 , 1 , 5 , 5 ]
print ( "The original list : " + str (test_list))
res = {}
i = 0
while i < len (test_list):
key = test_list[i]
start = i
while i < len (test_list) and test_list[i] = = key:
i + = 1
end = i - 1
res.setdefault(key, []).append((start, end))
print ( "The grouped dictionary : " + str (res))
|
Output
The original list : [1, 1, 5, 6, 5, 5, 6, 6, 6, 1, 5, 5]
The grouped dictionary : {1: [(0, 1), (9, 9)], 5: [(2, 2), (4, 5), (10, 11)], 6: [(3, 3), (6, 8)]}
Time Complexity: O(n), where n is the length of the input list. The approach iterates through the input list exactly once, and the inner loop executes a constant number of times for each element in the list.
Auxiliary Space: O(n), where n is the length of the input list. The approach creates a dictionary to store the grouped ranges, with each group represented as a tuple of start and end indices.
Method 3: Using itertools.groupby() – We first groups the consecutive elements in test_list using itertools.groupby(), and then maps the resulting groups to a dictionary with keys as the unique elements in the list and values as the indices of the groups. The indices are calculated using enumerate() and the start and end indices are computed based on the length of each group.
Python3
import itertools
test_list = [ 1 , 1 , 5 , 6 , 5 , 5 , 6 , 6 , 6 , 1 , 5 , 5 ]
groups = [(k, list (g)) for k, g in itertools.groupby(test_list)]
res = {k: [(i, i + len (g) - 1 ) for i, (k_, g) in enumerate (groups) if k_ = = k] for k, _ in groups}
print ( "The grouped dictionary : " + str (res))
|
Output
The grouped dictionary : {1: [(0, 1), (5, 5)], 5: [(1, 1), (3, 4), (6, 7)], 6: [(2, 2), (4, 6)]}
Time complexity: O(n), where n is the length of the input list test_list.
Auxiliary space: O(n), where n is the length of the input list test_list.
Method 4: Using numpy.split().
The algorithm works as follows:
- Convert the input list into a NumPy array.
- Use the np.diff() function to compute the difference between consecutive elements of the array, and add a -1 at the beginning and end of the result.
- Use the np.flatnonzero() function to find the indices of the non-zero elements in the result.
- Use the np.split() function to split the array into subarrays at the positions indicated by the non-zero indices.
- Iterate over the subarrays, and for each one:
a. Determine the key value (i.e., the first element of the subarray).
b. Determine the start and end indices of the subarray.
c. Add an entry to the result dictionary, with the key value as the key and a tuple containing the start and end indices as the value.
Python3
import numpy as np
test_list = [ 1 , 1 , 5 , 6 , 5 , 5 , 6 , 6 , 6 , 1 , 5 , 5 ]
arr = np.array(test_list)
splits = np.flatnonzero(np.diff(arr, prepend = - 1 , append = - 1 ))
groups = np.split(np.arange( len (test_list)), splits[ 1 :])
res = {}
for key, indices in zip (arr[splits[: - 1 ]], groups):
res.setdefault(key, []).append((indices[ 0 ], indices[ - 1 ]))
print ( "The grouped dictionary : " + str (res))
|
Output
The grouped dictionary : {1: [(0, 1), (5, 5)], 5: [(1, 1), (3, 4), (6, 7)], 6: [(2, 2), (4, 6)]}
The time complexity of this algorithm is O(n), where n is the length of the input list, because it involves a single pass over the input list, and each operation inside the loop takes constant time.
The auxiliary space is also O(n), because it involves creating a NumPy array and a dictionary with at most n entries.
Method 5:using a recursive function:
Algorithm:
1.Define a recursive function group_consecutive_range_indices that takes test_list, res and start as arguments.
2.Inside the function, check if res is None, if so create a defaultdict object to store the results.
3.Check if start is greater than or equal to the length of test_list, if so return the result as a dictionary.
4.Define end as start.
5.While end is less than the length of test_list and the element at index end is equal to the element at index start, increment end.
6.Append the range of indices from start to end-1 for the element at index start to the res dictionary.
7.Call the group_consecutive_range_indices function recursively with updated start and res values.
8.Outside the function, initialize test_list and call the group_consecutive_range_indices function.
9.Print the original list and the resulting grouped dictionary.
Python3
from collections import defaultdict
def group_consecutive_range_indices(test_list, res = None , start = 0 ):
if res is None :
res = defaultdict( list )
if start > = len (test_list):
return dict (res)
end = start
while end < len (test_list) and test_list[end] = = test_list[start]:
end + = 1
res[test_list[start]].append((start, end - 1 ))
return group_consecutive_range_indices(test_list, res, end)
test_list = [ 1 , 1 , 5 , 6 , 5 , 5 , 6 , 6 , 6 , 1 , 5 , 5 ]
print ( "The original list : " + str (test_list))
res = group_consecutive_range_indices(test_list)
print ( "The grouped dictionary : " + str (res))
|
Output
The original list : [1, 1, 5, 6, 5, 5, 6, 6, 6, 1, 5, 5]
The grouped dictionary : {1: [(0, 1), (9, 9)], 5: [(2, 2), (4, 5), (10, 11)], 6: [(3, 3), (6, 8)]}
Time Complexity: O(n), where n is the length of the input list. The function needs to traverse the entire list to group consecutive elements.
Auxiliary Space: O(n), where n is the length of the input list. The function uses a defaultdict object to store the results, which can have at most n distinct keys, and each key can have a list of ranges with at most n elements.
Similar Reads
Python | Group consecutive list elements with tolerance
Sometimes, we might need to group list according to the consecutive elements in the list. But a useful variation of this can also be a case in which we need to consider a tolerance level, i.e allowing a skip value between numbers and not being exactly consecutive but a "gap" is allowed between numbe
3 min read
Python - Extract elements with Range consecutive occurrences
Sometimes while working with data, we can have a problem in which we need to select some of the elements that occur range times consecutively. This problem can occur in many domains. Letâs discuss certain ways in which this problem can be solved. Method #1 : Using groupby() + list comprehension This
4 min read
Python - Group Consecutive elements by Sign
Given a list group of consecutive elements on the basis of signs. Input : test_list = [5, -3, 2, 4, 6, -2, -1, -7, -9, 2, 3] Output : [[5], [-3], [2, 4, 6], [-2, -1, -7, -9], [2, 3]] Explanation : Elements inserted into new list on sign change.Input : test_list = [-2,3,4,5,6,-3] Output : [[-2], [3,
3 min read
Python | Retain K consecutive elements
Sometimes while working with data, we can have a problem in which we need to select some of the elements that occur K times consecutively. This problem can occur in many domains. Let's discuss certain ways in which this problem can be solved. Method #1 : Using groupby() + list comprehension This tas
8 min read
Python - Consecutive elements maximum frequencies
Sometimes, while working with Python lists we can have a problem in which we need to extract the maximum frequencies of consecutive elements. This kind of problem can occur as application in many domains such as day-day programming and competitive programming. Let's discuss certain ways in which thi
5 min read
Python - Similar Consecutive elements frequency
Sometimes, while working with Python, we can have a problem in which we have to find the occurrences of elements that are present consecutively. This problem have usage in school programming and data engineering. Let's discuss certain ways in which this task can be performed. Method #1 : Using loop
5 min read
Python - Consecutive Triple element pairing
Sometimes, while working with lists, we need to triple pair up the like elements in list and then store them as lists of list. This particular task has itâs utility in many domains, be it web development or day-day programming. Letâs discuss certain ways in which this can be achieved. Method #1 : Us
4 min read
Python - Reorder for consecutive elements
Given a List perform reordering to get similar elements in consecution. Input : test_list = [4, 7, 5, 4, 1, 4, 1, 6, 7, 5] Output : [4, 4, 4, 7, 7, 5, 5, 1, 1, 6] Explanation : All similar elements are assigned to be consecutive. Input : test_list = [4, 7, 5, 1, 4, 1, 6, 7, 5] Output : [4, 4, 7, 7,
4 min read
Python - Filter consecutive elements Tuples
Given a Tuple list, filter tuples that are made from consecutive elements, i.e diff is 1. Input : test_list = [(3, 4, 5, 6), (5, 6, 7, 2), (1, 2, 4), (6, 4, 6, 3)] Output : [(3, 4, 5, 6)] Explanation : Only 1 tuple adheres to condition. Input : test_list = [(3, 4, 5, 6), (5, 6, 7, 2), (1, 2, 3), (6,
5 min read
Python - Test Consecutive Element Matrix
Given a Matrix, test if it is made of consecutive elements. Input : test_list = [[4, 5, 6], [7], [8, 9, 10], [11, 12]] Output : True Explanation : Elements in Matrix range from 4 to 12. Input : test_list = [[4, 5, 6], [7], [8, 18, 10], [11, 12]] Output : False Explanation : Elements not consecutive
6 min read