TL;DRimport bisect
def intervalo(lista, i, j):
left = bisect.bisect_left(lista, i)
right = bisect.bisect(lista, j)
return lista[left:right]
ExplanationNotice this section of your code:if el >= li:
pos_el1 = l.index(el)
elif el >= ls:
pos_el2 = l.index(el)
sublista = l[pos_el1:pos_el2]
The above code has 3 possibilities:el >= li then pos_el1 is created, because entered the 1st if;el >= ls then pos_el2 is created, because entered the 2nd if;el is smaller than both, li and ls, and no variable is created because it did not enter any if and you just create them within these ifs.Note that in no possible flow of this code the variables pos_el1 and pos_el2 can coexist, or only one exists, or just the other, never both are created in the same flow.This makes the posterior line: sublista = l[pos_el1:pos_el2] obligatoryly give error, because you are using one of the variables that will necessarily not be created.Possible solutions:List comprehension ( https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions )The simplest of all could be to use a https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions filtering only the items that fulfill your condition. As your list has the ordered values, this solution works well:def intervalo(lista, i, j):
return [item for item in lista if i <= item <= j]
lista_inicial = [12,14,15,16,18,20,24,26,28,32,34,38]
intervalo(lista_inicial, 13, 26)
[14, 15, 16, 18, 20, 24, 26]
If you still do not know the concept comprehensions, an equivalent version using for It would be like this:def intervalo(lista, i, j):
resultado = []
for item in lista:
if if i <= item <= j:
resultado.append(item)
return resultado
lista_inicial = [12,14,15,16,18,20,24,26,28,32,34,38]
intervalo(lista_inicial, 13, 26)
[14, 15, 16, 18, 20, 24, 26]
Slice ( https://docs.python.org/3/library/functions.html#slice )Can be used https://docs.python.org/3/library/functions.html#slice , as you did yourself, but it is necessary to treat when the values sought do not exist in the list, because if the values that limit your range do not exist in the list you will have to select the nearest index. One solution could be:def intervalo_slices(lista, i, j):
left, right = 0, len(lista)
for index, item in enumerate(lista):
if item < i:
# se for menor que o mínimo mostra do próximo em diante
left = index + 1
if item <= j:
# Se for maior que o máximo mostra até o próximo índice
right = index + 1
return lista[left:right]
The algorithm is simple:I cry left and right with default values 0 and the total size of the list (len(lista)), so if the flow does not enter any of the ifs the result will be lista[0:len(lista)] which is only a copy of the original list;Usage https://docs.python.org/3/library/functions.html#enumerate to have the indexes of the items that I am traveling and carry out the calculations (similar to the i that we see in ties for of other languages);Test on all iterations if item is less than the minimum.
If the condition is true, it means that the lower limit of our list is the following item, as it will be equal or greater than i;Test on all iterations if item is smaller or equal to the maximum, if yes, the index I want is also the next, as slices do not include the value of the right (e.g. [0, 1, 2, 3][:2] results in [0, 1]);Finally return the https://docs.python.org/3/library/functions.html#slice with the correct valuesIf you give one print within if you will see left and right receive values several times until conditions cease to be true. It’s not a very optimized solution, but it’s a more “handmade” algorithm and I wanted to show you what went wrong with your example with a possible solution to your line of reasoning.For a more optimized solution in this same line of reasoning, see the next session.Module bisect ( https://docs.python.org/3/library/bisect.html )Another way to solve the problem "what index of the list should make slice" is to use a https://pt.wikipedia.org/wiki/Pesquisa_bin%C3%A1ria to find in which position of the list should be made slice, even if the value does not exist in this list.The module https://docs.python.org/3/library/bisect.html was made to work with ordered sequences and binary search, so we can take advantage of a native python module to solve the problem with a https://pt.wikipedia.org/wiki/Complexidade_de_tempo of O(Log2 n) instead of O(n) as previous problems.For this we will use the functions https://docs.python.org/3/library/bisect.html#bisect.bisect and https://docs.python.org/3/library/bisect.html#bisect.bisect_left . Both have the same purpose and functioning, they serve to find out in which position of an orderly sequence a value must be inserted so that its ordination is maintained.For example:from bisect import bisect
lista = [0, 2, 4, 5, 8, 10]
index = bisect(lista, 3)
2
lista.insert(index, 3)
lista = [0, 2, 3, 4, 5, 8, 10]
└── posição retornada por bisect
See bisect returned the index 2, which is exactly where I can enter the value 3 on my list so that it is maintained.But what good is the bisect_left?Functions https://docs.python.org/3/library/bisect.html#bisect.bisect and https://docs.python.org/3/library/bisect.html#bisect.bisect_left differ only when the value sought already exists, that is, in the previous example could be used https://docs.python.org/3/library/bisect.html#bisect.bisect or https://docs.python.org/3/library/bisect.html#bisect.bisect_left for the result would be the same.When we look for the input index of an existing value in the sequence, we have two options:Insert in the same index of found value ( https://docs.python.org/3/library/bisect.html#bisect.bisect_left ).To enter the value 1 in the list [0, 1, 2, 3]:# ┌── valor encontrado
[0, 1, 1, 2, 3]
└── novo valor
Insert in the next index of the value found ( https://docs.python.org/3/library/bisect.html#bisect.bisect ).To enter the value 1 in the list [0, 1, 2, 3]:# ┌── valor encontrado
[0, 1, 1, 2, 3]
└── novo valor
In summary, the difference is whether the returned index is the same as the value found or the next. The code below illustrates the examples mentioned above:from bisect import bisect, bisect_left
lista = [0, 1, 2, 3]
indice = bisect(lista, 1)
2
indice_left = bisect(lista, 1)
1
Final code using bisectNow that you understood the concept, just use the bisect_left to correctly pick up the minimum index to use in slice and bisect to get the maximum index.import bisect
def intervalo(lista, i, j):
left = bisect.bisect_left(lista, i)
right = bisect.bisect(lista, j)
return lista[left:right]
ConclusionThese are some ways to do what you want, introduced the module bisect because besides being performatic and interesting, I find it important for the appreciated terms examples of practical use.I created this https://repl.it/@fernandosavio/SOPt-420004-6333 with all examples running.