根据值获取列表的列表索引范围

时间:2014-02-20 14:29:04

标签: python algorithm list

我有一个如下所示的列表:

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 )。在此先感谢您的帮助。

5 个答案:

答案 0 :(得分:1)

我建议使用bisectitertools.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)]

答案 1 :(得分: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)]

答案 2 :(得分:1)

由于值总是增加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]

答案 3 :(得分: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])

答案 4 :(得分: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