2016-09-29 3 views
0

Эта часть моего кода не масштабируется, если размер увеличивается.Извлечение элементов из списка при его обходе

Я перебираю свои данные и накапливаю их каждые dt Временное окно. Для этого я сравниваю значение нижнего и верхнего значения времени. Когда я достигаю верхней границы, я разбиваю на цикл для эффективности. В следующий раз, когда я запустил для цикла Я хочу начать не с самого начала, а из элемента, который я остановил ранее, для эффективности. Как я могу это сделать?

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

# Here I generate data for you to show my problem 
from random import randint 
import numpy as np 

dimension = 200 
times = [randint(0, 1000) for p in range(0, dimension)] 
times.sort() 
values = [randint(0, dimension) for p in range(0, dimension)] 
data = [(values[k], times[k]) for k in range(dimension)] 
dt = 50.0 
t = min(times) 
pixels = [] 
timestamps = [] 

# this is my problem 
while (t <= max(times)): 
    accumulator = np.zeros(dimension) 
    for idx, content in enumerate(data): 
     # comparing lower bound of the 'time' window 
     if content[1] >= t: 
      # comparing upper bound of the 'time' window 
      if (content[1] < t + dt): 
       accumulator[content[0]] += 1 
       # if I pop the first element from the list after accumulating, indexes are screwed when looping further 
       # data.pop(0) 
      else: 
       # all further entries are bigger because they are sorted 
       break 

    pixels.append(accumulator) 
    timestamps.append(t) 
    t += dt 
+0

Если вы разорвать цикл в свою собственную функцию, вы можете пройти начальный индекс цикла в качестве параметра (используйте [диапазон()] (https://docs.python.org/2/library /functions.html#range) в цикле). Затем, когда вы снова запустите цикл, вы можете вызвать его из индекса, который вы закончили. При первом вызове функция выполняет ноль.Параметр также будет первым параметром, с которым вы вызываете диапазон. –

+4

Если вы хотите удалить элементы, вы можете зайти в обратную сторону или создать копию списка или использовать понимание списка. См. [This] (http://stackoverflow.com/questions/1207406/remove-items-from-a-list-while-iterating-in-python) –

+0

спасибо! Мне нужно больше практики python, потому что range() мне не пришло в голову. Я пытался найти аналог итераторов C++. – beginh

ответ

0

В более простой форме, я думаю, что вы пытаетесь сделать:

In [158]: times=[0, 4, 6, 10] 
In [159]: data=np.arange(12) 
In [160]: cnt=[0 for _ in times] 
In [161]: for i in range(len(times)-1): 
    ...:  for d in data: 
    ...:   if d>=times[i] and d<times[i+1]: 
    ...:    cnt[i]+=1 
    ...:    
In [162]: cnt 
Out[162]: [4, 2, 4, 0] 

И вы пытаетесь сделать это data цикла более эффективным, разбив образуют петлю, когда d становится слишком большой, и путем запуска следующего цикла после элементов, которые уже были подсчитаны.

Добавление пролом легко, как вы сделали:

In [163]: cnt=[0 for _ in times] 
In [164]: for i in range(len(times)-1): 
    ...:  for d in data: 
    ...:   if d>=times[i]: 
    ...:    if d<times[i+1]: 
    ...:     cnt[i]+=1 
    ...:    else: 
    ...:     break 

In [165]: cnt 
Out[165]: [4, 2, 4, 0] 

Один из способов, чтобы пропустить подсчитанное материал должен заменить for d in data с петлей индекса; и отслеживать, где мы остановились в прошлый раз:

In [166]: cnt=[0 for _ in times] 
In [167]: start=0 
    ...: for i in range(len(times)-1): 
    ...:  for j in range(start,len(data)): 
    ...:   d = data[j] 
    ...:   if d>=times[i]: 
    ...:    if d<times[i+1]: 
    ...:     cnt[i]+=1 
    ...:    else: 
    ...:     start = j 
    ...:     break 
    ...:     
In [168]: cnt 
Out[168]: [4, 2, 4, 0] 

pop на основе версии требует, чтобы я работать со списком (мой data является массивом), необходимо вставить значение обратно на перерыв

In [186]: datal=data.tolist() 
In [187]: cnt=[0 for _ in times] 
In [188]: for i in range(len(times)-1): 
    ...:  while True: 
    ...:   d = datal.pop(0) 
    ...:   if d>=times[i]: 
    ...:    if d<times[i+1]: 
    ...:     cnt[i]+=1 
    ...:    else: 
    ...:     datal.insert(0,d) 
    ...:     break 
    ...:    
In [189]: cnt 
Out[189]: [4, 2, 4, 0] 
In [190]: datal 
Out[190]: [10, 11] 

Это не идеально, так как у меня все еще есть предметы в списке в конце (мой times не покрывает весь диапазон data). Но он проверяет идею.

Вот что-то ближе к попытке:

In [203]: for i in range(len(times)-1): 
    ...:  for d in datal[:]: 
    ...:   if d>=times[i]: 
    ...:    if d<times[i+1]: 
    ...:     cnt[i]+=1 
    ...:     datal.pop(0) 
    ...:    else: 
    ...:     break 
    ...:  

Основное различие заключается в том, что я итерацию на копии datal. Таким образом, pop влияет на datal, но не влияет на текущую итерацию. По общему признанию, для копирования стоит стоимость, поэтому ускорение может быть значительным.

Другой подход заключается в петле на data, и шаг time как t и t+dt границы пересекаются.

In [222]: times=[0, 4, 6, 10,100] 
In [223]: cnt=[0 for _ in times]; i=0 
In [224]: for d in data: 
    ...:  if d>=times[i]: 
    ...:   if d<times[i+1]: 
    ...:    cnt[i]+=1 
    ...:   else: 
    ...:    i += 1 
    ...:    cnt[i]+=1 
    ...:    
In [225]: cnt 
Out[225]: [4, 2, 4, 2, 0]