例如,a = [12,11,5,7,2,21,32,13,6,42,1,8,9,0,32,38],我想找到那个指数范围它中的值小于10.是否有一种简单的方法可以返回[[2,4],[8],[10,13]]的索引范围?
我写了一个函数,但觉得它很乏味:
def indexscope(dlist):
newinterval = True
scope = []
for i in range(len(dlist)):
if dlist[i] < 10:
if newinterval:
interval = [i]
newinterval = False
else:
k = i
else:
if not newinterval:
interval[1] = k + 1
scope.append(interval)
newinterval = True
return scope
对于上面提到的例子,我可以使用indexscope(a)来获得我的结果。
但是如果我想获得另一个需要值&gt;的索引范围呢? 20下次?丑陋写了另一个功能? 是否有一种简单的方法可以将索引范围提升到一般水平?
1.是的,正如你们中的一些人指出的那样,我需要的是指数范围。我稍后将处理每个索引范围内的元素。 让每个连续元素保持在相同范围非常重要。
因此,[[2,4],[8],[10,13]]和[[2,3,4],[8],[10,11,12,13]]的返回值可以都被接受了。
2.目前,@ TigerhawkT3的答案可以满足我在我的例子中的要求。 @ DTing的回答引起了我的进一步要求。但我仍然找到一种更简单的方式。
3.我终于得到了两行答案,请参阅@ TigerhawkT3的答案以及互联网上的其他一些答案。现在我可以放弃功能定义,只需替换我需要的标准。谢谢大家帮助我的努力。
l = [idx for idx,value in enumerate(a) if value<10]
print [list(g) for _,g in groupby(l,key=lambda n,c=count():n-next(c))]
答案 0 :(得分:2)
您可以让函数将函数作为参数用作构建区间的谓词:
def indexscope(dlist, predicate):
scope = []
start = end = -1
for i, v in enumerate(dlist):
if predicate(v):
if start == -1:
start = end = i
continue
if end + 1 == i:
end = i
else:
scope.append([start] if start == end else [start, end])
start = end = i
if start != -1:
scope.append([start] if start == end else [start, end])
return scope
a = [12,11,5,7,2,21,32,13,6,42,1,8,9,0,32,38]
def less_than_10(n):
return n < 10
print(indexscope(a, less_than_10))
print(indexscope(a, lambda x: x > 20))
[[2, 4], [8], [10, 13]]
[[5, 6], [9], [14, 15]]
与scipy:
import numpy as np
import scipy.ndimage as nd
def passing_ranges(a, predicate):
return nd.find_objects(nd.label(predicate(a))[0])
结果以slice
个对象的形式返回,但这对您有利,因为您可以将它们用于原始的np数组:
small_a = [12,11,5,7,2,21,32,13,6,42,1,8,9,0,32,38]
small_np_array = np.array(small_a)
valid_ranges = passing_ranges(small_np_array, lambda n: n < 10)
for r in valid_ranges:
print(r[0], small_np_array[r])
slice(2, 5, None) [5 7 2]
slice(8, 9, None) [6]
slice(10, 14, None) [1 8 9 0]
<强>基准强>
large_a = [12,11,5,7,2,21,32,13,6,42,1,8,9,0,32,38]*1000000
large_np_array = np.array(large_a)
%timeit passing_ranges(large_np_array, lambda x: x < 10)
1 loops, best of 3: 1.2 s per loop
%timeit indexscope(large_a, lambda n: n < 10)
1 loops, best of 3: 6.99 s per loop
这是你的答案,我甚至内联谓词来删除一个函数调用:
from itertools import groupby, count
def xibinke(a):
l = [idx for idx,value in enumerate(a) if value<10]
return [list(g) for _,g in groupby(l,key=lambda n,c=count():n-next(c))]
%timeit xibinke(large_a)
1 loops, best of 3: 14.6 s per loop
答案 1 :(得分:2)
a = [12,11,5,7,2,21,32,13,6,42,1,8,9,0,32,38]
indices = [idx for idx,val in enumerate(a) if val < 10]
这会创建list
个索引:
[2, 3, 4, 8, 10, 11, 12, 13]
我建议保持这种方式以便于解析,但您也可以按如下方式将其转换为范围:
ranges = [[]]
for val in indices:
if not ranges[-1] or ranges[-1][-1] == val-1:
ranges[-1].append(val)
else:
ranges.append([val])
这会创建list
范围:
[[2, 3, 4], [8], [10, 11, 12, 13]]
现在取出中间位置:
ranges = [[item[0],item[-1]] if len(item) > 1 else item for item in ranges]
结果:
[[2, 4], [8], [10, 13]]
答案 2 :(得分:1)
如果您准备使用numpy,要获取所有元素的索引,在numpy库中有一个名为numpy.nonzero()
的简单函数,您必须传入要检查的条件。
示例 -
In [1]: import numpy as np
In [2]: n = np.array([11,23,4,5,1222,33,6,10])
In [6]: ni = np.nonzero(n < 10)
Out[6]: (array([2, 3, 6]),)
In [7]: ni[0]
Out[7]: array([2, 3, 6])
在此之后,返回你想要的索引的第一个元素。
如果您只是想要满足特定条件的值,那么numpy库中还有另一个非常简单的解决方案可以满足您的需求,使用的函数称为 - numpy.where
,请注意这将给出值那些,而不是索引。例子 -
import np
a = [12,11,5,7,2,21,32,13,6,42,1,8,9,0,32,38]
npa = np.array(a)
np.where(a < 10)
>> array([5,7,2,6,1,8,9,0])
答案 3 :(得分:1)
获取无效索引的单行代码,并按案例生成范围
# get invalid indices
l = [idx for idx, value in enumerate(dlist) if value<10]
scope = []
for value in l:
if scope and scope[-1][-1] == value-1:
scope[-1] = scope[-1][0:1] + [value]
else:
scope.append([value])
# scope is exactly what you wanna
具有lambda
功能的单行代码:
scope = []
l = [idx for idx, value in enumerate(dlist) if value<10]
# output like [[2, 4], [8], [10, 13]]:
map(lambda x: (len(scope[-1]) == 1 or scope[-1].pop(-1)) and scope[-1].append(
x) if scope and scope[-1][-1] == x - 1 else scope.append([x]), l)
# output like [[2,3,4],[8],[10,11,12,13]]
map(lambda x: scope[-1].append(x) if scope and
scope[-1][-1] == x - 1 else scope.append([x]), l)
答案 4 :(得分:0)
参考@ TigerhawkT3的回答,并在互联网上搜索,我得到了这个答案:
from itertools import groupby,count
a = [12,11,5,7,2,21,32,13,6,42,1,8,9,0,32,38]
l = [idx for idx,value in enumerate(a) if value<10]
print [list(g) for _,g in groupby(l,key=lambda n,c=count():n-next(c))]
它给出了范围列表:
[[2, 3, 4], [8], [10, 11, 12, 13]]