Python - 在列表中根据不同标准查找前后值
我想在Python中遍历一个数字列表,找到某个特定元素的索引,然后找出与它最近的符合某些条件的元素。我找不到任何内置的函数可以让我在列表中保持当前位置,以便我可以根据不同的搜索条件找到前后的项目。Python中有这样的东西吗?
我有一个很长的数字列表,我想在其中找到一个特定的重复模式。
比如说:
L = [1, 1, 3, 5, 7, 5, 1, 2, 1, 1, 1, 8, 9, 1, 1, 1]
假设我想通过寻找列表中第一个大于4的数字的索引来找到“峰值”,然后再找出两边最近的小于2的数字的索引。接着我想找到下一个峰值,重复这个过程。(实际上这个模式比这复杂得多。)
所以在这个例子中,我最终想要的输出是1:6, 10:13。
我用这个来找到第一个值:
a = next(i for i, v in enumerate(L) if v > 4)
或者用这个来找到所有大于4的值,以便后面进行分组:
indexes = [i for i, v in enumerate(L) if v > 4]
我尝试过next、iter、生成器、各种for循环等等,但都没有成功。我也看过islice,但感觉每找到一个索引就把列表切成两部分,然后在这两部分上进行正向和反向搜索,这样做太复杂了。难道没有更简单的方法吗?
任何帮助都将非常感谢。
2 个回答
2
这个方法可以找到你提到的峰值,但需要知道列表的起始索引,以便确定从哪里开始搜索:
def findpeaks(lst, index, v1, v2):
l = lst[index:]
ele = next(i for (i, v) in enumerate(l) if v > v1)
idx = ele - next(i for (i, v) in enumerate(l[:ele+1][::-1]) if v < v2)
jdx = ele + next(i for (i, v) in enumerate(l[ele:]) if v < v2)
# Returns a tuple containing:
#
# the index of the element > v1
# the index of the element < v2 (found before the element > v1),
# the index of the element < v2 (found after the element > v1).
return (ele + index, idx + index, jdx + index)
这个过程是这样进行的:
- 首先找到第一个值符合条件的元素(在你的例子中是大于4)
- 然后找到这个索引之前的元素,看看哪个元素符合第二个值的条件(小于2)。这个过程是通过从第一步找到的索引开始,创建一个列表的切片,然后把这个切片反转过来。接着,你找到的索引需要从第一步的索引中减去。
- 接下来,向前搜索,创建一个原始列表的切片,从那里继续查找。
- 最后的结果需要考虑到起始索引,所以要把这个索引加到结果中。就这样。
举个例子:
L = [1, 1, 3, 5, 7, 5, 1, 2, 1, 1, 1, 8, 9, 1, 1, 1]
print findpeaks(L, 0, 4, 2) # prints (3, 1, 6)
print findpeaks(L, 6, 4, 2) # prints (11, 10, 13)
接下来的明显步骤是找到所有符合这个条件的元素。一个建议是可以把这个过程做成递归的——不过这个你可以自己尝试。
2
我会使用一个生成器函数,并在遍历输入数据时记录符合你条件的索引:
L = [1, 1, 3, 5, 7, 5, 1, 2, 1, 1, 1, 8, 9, 1, 1, 1]
def peak_groups(l):
start_i = 0
peak_i = None
for i,x in enumerate(l):
if peak_i is None:
# look for start of peak group, or peak itself
if x < 2:
start_i = i
elif x > 6:
peak_i = i
else:
# look for end of peak group
if x < 2:
yield (start_i, peak_i, i)
start_i = i
peak_i = None
# finally check edge condition if we reached the end of the list
if peak_i is not None:
yield (start_i, peak_i, i)
for group in peak_groups(L):
print group
这样会得到:
(1, 4, 6)
(10, 11, 13)
好处是你只需要遍历输入数据一次。虽然在实际情况中,分组条件可能没有那么简单。
你需要考虑如果多个“峰值组”重叠时应该怎么处理,目前这个方法并没有找到组中最大的峰值,但这应该是一个好的起点。