2016-12-27 2 views
4

получить данные в следующем формате:обратного индекс последнего ненулевого элемента в списке

[-2, -2, 0, 0, 0, 0, 0] 
[-2, 20, -1, 0, 3, 0, 0] 

с каждой линией другим входа. Списки могут быть длиннее 7 элементов. Мне нужно вернуть индекс позиции последнего ненулевого элемента, так:

[-2, -2, 0, 0, 0, 0, 0] 
>>> 1 
[-2, 20, -1, 0, 3, 0, 0] 
>>> 4 

Следующий код делает это большую часть времени:

def getIndex(list): 
    for element in reversed(list): 
     if element != 0: 
      return list.index(element) 

Однако, это не работает, когда являются двумя одинаковыми номерами, как в первом примере выше, который возвращает 0, потому что -2 находится как в 0-й, так и в 1-й позиции списка.

Как получить индекс последнего ненулевого элемента списка, даже если есть элементы с одинаковым значением?

ответ

1

следующее решения проходит все мои тесты:

def getLastNonZeroIndex(originalList): 

    # Create a new list from the old list 
    # so changes don't change the old list 
    newList = list(originalList) 

    # Keep checking to see if last item equals 0 
    # If it does, remove it from newList 
    while newList[-1] == 0: 
     newList.pop() 

    # Once the item at newList[-1] != 0 
    # Return index of the last element 
    return len(newList)-1 

Я до сих пор подозреваю, что есть лучший способ сделать это, поэтому, пожалуйста, поделитесь любыми альтернативными решениями, которые вы могли бы иметь.

3

Ваше решение изменяет список постоянно, я думаю, что даже наивная for петли лучше:

last_nonzero_index = None 
for idx, item in enumerate(originalList): 
    if item != 0: 
     last_nonzero_index = idx 
2

вот версия чисто из генераторов: ни один из списков не копируются.

a = [-2, -2, 0, 0, 0, 0, 0] 
b = [-2, 20, -1, 0, 3, 0, 0] 

def index_of_last_nonzero(lst): 
    for i, value in enumerate(reversed(lst)): 
     if value != 0: 
      return len(lst)-i-1 
    return -1 

print(index_of_last_nonzero(lst=a)) # -> 1 
print(index_of_last_nonzero(lst=b)) # -> 4 

идея заключается в том, чтобы перебирать в список reversed при подсчете (с enumerate). если список равен нулю -1.

4

Вы можете итерируем reversed список и возвращает первый элемент, который не является нулевым, как этот

>>> def get_last_non_zero_index(d, default=None): 
...  rev = (len(d) - idx for idx, item in enumerate(reversed(d), 1) if item) 
...  return next(rev, default) 
... 
>>> print(get_last_non_zero_index([-2, -2, 0, 0, 0, 0, 0])) 
1 
>>> print(get_last_non_zero_index([-2, 20, -1, 0, 3, 0, 0])) 
4 
>>> print(get_last_non_zero_index([0, 0, 0])) 
None 
>>> print(get_last_non_zero_index([])) 
None 

Значение default будет возвращено, если функция не может найти ненулевое значение.

+0

очень хорошее использование 'next'! +1 –

1

Вот это вещий и оптимизированный подход с использованием itertools.takewhile():

from itertools import takewhile 
from operator import not_ 
len(lst) - sum(1 for _ in takewhile(not_, reversed(lst))) - 1 

Демо:

In [115]: lst = [-2, -2, 0, 0, 0, 0, 0] 
In [118]: len(lst) - sum(1 for _ in takewhile(lambda x : not bool(x), lst[::-1])) - 1 
Out[118]: 1 

In [119]: lst = [-2, 20, -1, 0, 3, 0, 0] 

In [120]: len(lst) - sum(1 for _ in takewhile(lambda x : not bool(x), lst[::-1])) - 1 
Out[120]: 4 

Вот benchmarck с другими ответами на более длинный список:

In [141]: lst = lst * 1000 

In [142]: %timeit len(lst) - len(list(takewhile(not_, reversed(lst)))) - 1 
1000000 loops, best of 3: 758 ns per loop 

In [143]: %timeit get_last_non_zero_index(lst) 
1000000 loops, best of 3: 949 ns per loop 

In [146]: %timeit index_of_last_nonzero(lst) 
1000000 loops, best of 3: 590 ns per loop 
1

Список понимание делает трюк:

a = [-2, 20, -1, 0, 3, 0, 0] 
ls = [i for i, e in enumerate(a) if e != 0] 
print(ls) 

выход:

[0, 1, 2, 4] 
+0

Мне нравится, что это может быть сведено к одной строке: 'return [index for index, item in enumerate (lst) if item! = 0] [- 1]' – Vincent

+0

Это один из главных преимуществ его использования , – Inconnu

1
n_l = [] 
for i,v in enumerate(l): #enumerate returns the index - i, and value-v 
    if v != 0: 
     n_l.append(i) #keep the index if the value is not 0 

n_l = sorted(n_l) #we then sort the list of indecies from least to greatest. the greatest index will be the last 
greatest_non_zero_index = n_l[-1] #grab the last index 

Heres другой способ сделать это в одной строке!

greatest_non_zero_index = sorted([i for i,v in enumerate(l) if v != 0])[-1] 
+0

У вас есть что-то? Не перечисляет ли 'list' список в порядке, так что' n_l' уже отсортирован? – Teepeemm

1

должны работать:

def last_non_zero_index(my_list): 
    temp = my_list[:] 
    while temp[-1] == 0: 
     del temp[-1] 
    return len(temp) - 1 

Выход:

>>> my_list = [-2, -2, 0, 0, 0, 0, 0] 
>>> last_non_zero_index(my_list) 
1 
>>> my_list = [-2, 20, -1, 0, 3, 0, 0] 
>>> last_non_zero_index(my_list) 
4 
Смежные вопросы