0

我想知道如何从一系列值中获得一系列范围。我的意思是假设我有一个数字列表:list_values = [4, 3, 4, 4]

我想把它转换成这样的一系列范围(暂时忽略数据的结构):

0: 0 - 4
1: 4 - 8
2: 8 - 13
3: 13 - 18

其中第 i 个范围的大小对应于数字列表中的第 i 个索引。

这是我迄今为止尝试过的(以及相同基本逻辑的其他变体)。为简单起见,并且因为我坚持这一点,我现在只计算了“开始”值,即范围的开始值(0、4、8、13 ...):

range_start = [0] 
for i, list_values in enumerate(list):
    range_start[i+1] = range_start[i] + list_values[i] + 1

这里的逻辑本质上是递归的,即开始范围的下一个值等于前一个值,加上第 (i-1) 个 list_value,再加上 1。注意循环的第一次迭代,range_start[1] = range_start[0] + list_value[0] + 1 = 4

但是,我不断收到错误消息TypeError: 'int' object is not subscriptable。我很困惑,因为我只做整数数学,而不是任何子集。

我希望输出是某种形式的范围,作为类似于此的列表或元组:

[[0, 4], [4, 8], [8, 13], [13, 18]]

任何帮助都很棒,谢谢!

4

4 回答 4

2

您可以使用itertools.accumulate来生成右端点列表,然后使用第二次迭代来生成左端点。右端点随着您添加存储桶宽度而增长,并且任何给定点的左端点是最后一个右端点加一。

from itertools import accumulate

list_values = [4, 3, 4, 4]

ranges = []

endpoints = list(accumulate(list_values))

for idx, value in enumerate(endpoints):
    # These ranges are closed on the left and 
    # the right.
    if idx == 0:
        ranges.append((1, value))
    else:
        ranges.append((endpoints[idx-1] + 1, value))
print(ranges)
[(1, 4), (5, 7), (8, 11), (12, 15)]

你的原因IndexError是它list_values是你列表的一个元素(一个整数;你用这个名字隐藏了你的外部列表)并list_values[i]尝试访问它,就好像它是一个列表一样。

于 2021-03-16T23:00:46.883 回答
2

如果您想要一个答案而不导入任何东西。

list_values = [4, 3, 4, 4]
range_start = []
start = 0
for i, k in enumerate(list_values):
    if start == 0:
        new_range = [start, start + k]
    else:
        new_range = [range_start[i-1][1], start + k]
    range_start.append(new_range)
    start += k + 1

为您提供以下range_start输出:[[0, 4], [4, 8], [8, 13], [13, 18]]

于 2021-03-16T23:18:03.777 回答
1

我想出了这个:

from collections import defaultdict

result = defaultdict(list)

prev = 0
for idx, n in enumerate(l):
  for i in range(prev, prev + n + 1):
    result[idx].append(i)
  prev = i + 1

print(result)

输出:

defaultdict(<class 'list'>, {0: [0, 1, 2, 3, 4], 1: [5, 6, 7, 8], 2: [9, 10, 11, 12, 13], 3: [14, 15, 16, 17, 18]})

编辑灵感来自@crcvd 的回答:

from itertools import accumulate

l= [4, 3, 4, 4]

result = {}
prev = 0
for idx, last in enumerate(accumulate(l)):
  result[idx] = list(range(idx + prev, last + idx + 1))
  prev = last
于 2021-03-16T23:21:34.023 回答
0

您可以使用列表推导zip

l = [4, 3, 4, 4] 
k = [sum(l[:i])+a+i for i, a in enumerate(l)]
#as full ranges
result = [list(range(a, b+1)) for a, b in zip([0]+k[:-1], k)]
#start and end indices:
result = list(zip([0]+k[:-1], k))

输出

[[0, 1, 2, 3, 4], [4, 5, 6, 7, 8], [8, 9, 10, 11, 12, 13], [13, 14, 15, 16, 17, 18]]
[(0, 4), (4, 8), (8, 13), (13, 18)]
于 2021-03-17T00:16:41.703 回答