def is_not_divisible_by_any(num, divs):
return all(num % divisor for divisor in divs)
def get_idx_of_concated_list(the_list, idx):
# Get the start, end and steps
start, end = the_list[0].start, the_list[0].stop
shifted_end = end - start
steps = [r.step for r in the_list]
# Get the number of numbers non-divisble by the steps until the given index (inclusive)
num_not_divisibles = sum(is_not_divisible_by_any(num, steps) for num in range(idx+1))
# The first candidate will be the given index + the above number of non-divisibles
candidate = idx + num_not_divisibles
# Forward by one till it is divisible by any of the steps
while is_not_divisible_by_any(candidate, steps):
candidate += 1
# Check if the given index was valid
if candidate > shifted_end:
raise ValueError("The given index with those ranges exceed the stop value")
# Since assumed start = 0, add the original start
return candidate + start
# Example:
concat_list = [range(0, 1_000_000, 2), range(0, 1_000_000, 3), range(0, 1_000_000, 7)]
idx = 225_000
print(get_idx_of_concated_list(concat_list, idx))
# 289286
Explanation: without loss of generality, let's assume that the start is 0 (we can easily add the original start back at the end as you will see). Then, we essentially have the following sequence:
0, 1, 2, 3, 4, 5, ..., stop-1
If, for this sequence, we were asked to find value at x
'th index, we'd directly say x
as the answer. However, the steps of the ranges skip some values in this sequence. For example, if steps are 2 and 3, we would have 0, 2, 3, 4, 6, ..
and so on. So if we can find the number of those skipped numbers that are not divisible by any of the given steps (till the given index, inclusive), then we would simply add it and get a candidate for the solution.
But the candidate still may not be divisible by any of the steps.(e.g consider your example in the question, where the number of non-divisibles would be 2 (1 and 5) and we add 2 to given index 5 and get 7; but this does not evenly divide 2 or 3). Therefore, we do an incremental search from the candidate
and on, till we find our desired value. And lastly, since we assumed start as 0, we add the original start value back to get the result.
Edit: I added a check for the index so that it does not exceed the stop value.
start
,stop
, allsteps
– Damaraland