2014-02-20 4 views
0

У меня есть список, который выглядит следующим образом:Получить диапазон индекса списка из списка в зависимости от значений

Values = [0,0,1,1,1,1,1,2,2,2,3,3,3,3,3,3,4,4,4,5,5,5,5] 

Я хотел бы получить индекс колеблется зависимости от значений. Например, для значения «0» Я хотел бы получить:

IndexRange0 = range(0,2) = [0,1]  
#the element "0" is taking the positions 0 and 1 of the list "Values" 

для значения «1» Я хотел бы получить:

IndexRange1 = range(2,7) = [2,3,4,5,6] 

и т.д. В конце концов, я хотел бы получить «список этих диапазонов», скажем:

FinalOutput = [IndexRange0, IndexRange1, .... IndexRange5] 

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

Примечание: цифры будут постоянно увеличиваться. Длина диапазонов - это переменные (на этот раз есть 2 «нули», в следующий раз они могут быть 5 и т. Д.), Но его порядок всегда увеличивается один за другим (будет набор из 0, затем набор из 1, затем набор из 2 и т. д. до целого числа нефиксированных n). Заранее спасибо за вашу помощь.

+0

Я не могу понять, что вы называете «дорогими конструкциями». Это проблема O (N) с прямым решением. –

ответ

1

Я бы предложил либо bisect, либо itertools.takewhile, в зависимости от того, как вы планируете его использовать.

С Bisect:

import bisect 

def index_range(n, lst): 
    return (bisect.bisect_left(lst, n), bisect.bisect_right(lst, n)) 

def final_output(rng, lst): 
    return [index_range(n, lst) for n in rng] 

values = [0,0,1,1,1,1,1,2,2,2,3,3,3,3,3,3,4,4,4,5,5,5,5] 
print(final_output(range(0,6), values)) 

дает

[(0, 2), (2, 7), (7, 10), (10, 16), (16, 19), (19, 23)] 
+0

Просто попробовал это. Конечно, цифры не обязательно между 0 и 5, но я могу просто сделать 'UniqueValues ​​= list (set (Values))', а затем повторить для каждого значения 'UniqueValues' вашу функцию. Удивительно, большое спасибо! –

0
read the first value 
start a run 
until end-of-list 
    read a value 
    if differs from current 
    finish the run 
    start a new run 
    else 
    lengthen the run 
finish the run 
+0

Да, я построил что-то вроде этого (может быть, даже немного дольше), но решение Hugh выше выглядит намного элегантнее, я бы сказал, 3 строки кода и отличный результат;) –

+0

Это решение занимает время 'O (m. lg (n)) ', для' m' отличные значения среди 'n'. Не зная о 'm', фактическая сложность может варьироваться от' O (lg (n)) 'до' O (n.log (n)) '. Но есть небольшое обман в том смысле, что вы просили сообщить все индексы, а не только индексы расщепления. Таким образом, это решение в лучшем случае «O (n)» и в худшем случае «O (n.lg (n))». –

1

Использование itertools.groupby:

from itertools import groupby 
from operator import itemgetter 
Values = [0,0,1,1,1,1,1,2,2,2,3,3,3,3,3,3,4,4,4,5,5,5,5] 
output = [] 
for k, g in groupby(enumerate(Values), key=itemgetter(1)): 
    start = next(g)[0] 
    for end, _ in g: pass 
    output.append((start, end+1)) 
print output 

Выход:

[(0, 2), (2, 7), (7, 10), (10, 16), (16, 19), (19, 23)] 
+0

Ницца, спасибо :) –

1

Поскольку значения всегда увеличиваясь на единицу, вот еще один способ сделать это без явного подсчета числа вхождений для каждого значения:

>>> Values = [0,0,1,1,1,1,1,2,2,2,3,3,3,3,3,3,4,4,4,5,5,5,5] 
>>> starts = [Values.index(i) for i in range(Values[-1] + 1)] + [len(Values)] 
>>> print starts 
[0, 2, 7, 10, 16, 19, 23] 
>>> ranges = [range(starts[i], starts[i + 1]) for i in range(len(starts) - 1)] 
>>> for r in ranges: 
... print r 
... 
[0, 1] 
[2, 3, 4, 5, 6] 
[7, 8, 9] 
[10, 11, 12, 13, 14, 15] 
[16, 17, 18] 
[19, 20, 21, 22] 
1

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

L=[0,0,0,2,2,2,4,5,6,6,7] 

еще возрастающей последовательности, но вы не можете знать, какое значение является второй диапазон, если вы не держите ссылку на это значение, вот простой код, который :

prev=L[0] 
f_index=0 
l_index=-1 
info = {} 
for index, item in enumerate(L): 
    if prev != item: 
     l_index=index-1 
     info[prev]=(f_index,l_index) 
     prev=item 
     f_index=index 
info[prev]=(f_index,index) 
print info 

результат будет следующим:

{0: (0, 2), 2: (3, 5), 4: (6, 6), 5: (7, 7), 6: (8, 9), 7: (10, 10)} 

теперь вы можете иметь дело с ним как 2D список, чтобы сделать выбор вам нужно т.е.

range(info[number][0],info[number][1]) 
+0

Отличное предложение, спасибо! –

Смежные вопросы