Reputation: 965
I have the following list of numbers:
numbers = numbers = [ 1, 3, 11, 12, 14, 15, 16, 3, 4, 6]
I would like to get the start and end index of the longest consecutive range of numbers. By consecutive range, I mean an integer range of number without skipping, i.e. 1,2,3,4,5...
This is how I have done it:
def get_longest_consecutive_numbers(numbers):
# 1. Split the numbers list into sublists of consecutive numbers
split_list = []
j = 0
for i in range(1,len(numbers)-1):
if numbers[i]+1 is not numbers[i+1]:
split_list.append(numbers[j:i])
j = i
# 2. Find index of longest sublist (of consecutive numbers)
longest_sublist_index = max((len(l), i) for i, l in enumerate(split_list))[1]
# 3. Concatenate all sublists up to this index back together
rest = split_list[:longest_sublist_index]
concat_list = [j for i in rest for j in i]
# 4.
# Start Index: Length of concatenated list
# End Index: Start Index + Length of longest sublist in split_list
start_index = len(concat_list)
end_index = start_index + len(split_list[longest_sublist_index])
return start_index, end_index
If I apply my function to the list of numbers:
get_longest_consecutive_numbers(numbers)
I get:
(3, 6)
which is correct... but...
I was wondering if there is a more straight-forward (better) way to do this ?
Upvotes: 0
Views: 2923
Reputation: 1938
How about using a 2 pointer approach:
set start=0, end=0
set bestLen=1, bestStart=0
while end < len(numbers) - 1
if numbers[end] + 1 == numbers[end + 1] then increase end; set bestLen = max(bestLen, end-start) (also set bestStart = start if you just updated bestLen)
else increase end; set start = end
return the range [bestStart ... bestStart + bestLen]
You'll get O(n) time and O(1) extra space.
Upvotes: 1
Reputation: 21
@ncica 's answer will not work if the longest sequence goes till the last element of the given list. Because I have small reputation, I cannot comment on @ncica's answer and so I will write the code in this separate answer. It is a modified version of @ncica's answer that should work for this case as well:
def longest(numbers):
my_max, count_ = 1, 1
start_idx, end_idx = 0, 0
for i in range(len(numbers)-1):
# if difference between number and his follower is 1,they are in sequence
if numbers[i+1]-numbers[i] ==1:
count_ = count_+1
else:
if count_ > my_max :
my_max = count_
end_idx = i
start_idx = i+1 - my_max
# Reset counter
count_ = 1
if count_ > my_max:
my_max = count_
end_idx = i+1
start_idx = i+2-my_max
return (start_idx,end_idx,my_max)
Upvotes: 1
Reputation: 971
You can also use recursion for it:
numbers = [1, 3, 11, 12, 14, 15, 16, 3, 4, 6]
def getMaxConsecutiveInd(index):
if numbers[index] + 1 == numbers[index + 1]:
# call the functions if values are cosecutive to check next value
return getMaxConsecutiveInd(index + 1)
# return last index for cosecutive numbers
return index
max_length, start_index, end_index = 0,0,0
i = 0
while i < len(numbers) - 1:
con_index = getMaxConsecutiveInd(i)
# if available max_length is less than new_max_length(con_index - i)
# then change start_index and end_index
if max_length < con_index - i:
max_length = con_index - i
start_index = i
end_index = con_index
# change value of i to latest con_index if i != con_index
if i == con_index:
i = i + 1
else:
i = con_index
print(start_index, end_index, max_length)
Output: (4,6,2)
numbers = [1, 2, 3, 4, 5, 6, 7, 11, 12, 14, 15, 16, 17, 18, 3, 4, 6]
Output: (0,6,6)
Upvotes: 2
Reputation: 7206
numbers = [ 1, 3, 11, 12, 14, 15, 16, 3, 4, 6]
def longest(numbers):
max, count_ = 1, 1
start_idx, end_idx = 0, 0
for i in range(len(numbers)-1):
# if difference between number and his follower is 1,they are in sequence
if numbers[i+1]-numbers[i] ==1:
count_ = count_+1
else:
if count_ > max :
max = count_
end_idx = i
start_idx = i+1 - max
# Reset counter
count_ = 1
return (start_idx,end_idx,max)
print (longest(numbers))
output:
(4, 6, 3) #start_idx, end_idx, len
Upvotes: 2
Reputation: 43494
You can use numpy.diff
to calculate the differences between successive elements in your list, and then use itertools.groupby
to collect those elements with differences equal to 1.
import numpy as np
from itertools import groupby
from operator import itemgetter
def get_longest_consecutive_numbers(numbers):
idx = max(
(
list(map(itemgetter(0), g))
for i, g in groupby(enumerate(np.diff(numbers)==1), itemgetter(1))
if i
),
key=len
)
return (idx[0], idx[-1]+1)
print(get_longest_consecutive_numbers(numbers))
#(4,6)
Upvotes: 1
Reputation: 610
Let's have a bit of fun :
Create the range in which the list is included
Symmetric difference of that with the list
Compute the max distance between two following numbers (gives you the max length)
Get the index of the start and end point
Here is the code :
def longest_weird(numbers):
delta = list(set(range(max(numbers))).symmetric_difference(numbers))
start,end = 0,0
maxi = 0
for i,x in enumerate(delta[:-1]):
aux = max(maxi,delta[i+1]-x)
if aux != maxi:
start,end = (x+1,delta[i+1]-1)
maxi = aux
return numbers.index(start),numbers.index(end)
Upvotes: 1