2013-02-13 112 views
2

总结了范围我有一个整数列表:生成一个列表

list = [a,b,c,d] 

我想将它转化成这些范围:

0..a 
a+1..a+b 
a+b+1..a+b+c 
a+b+c+1..a+b+c+d 

任何想法如何做到这一点在Python?

感谢

+0

那些是你真正想要的范围? – mgilson 2013-02-13 14:30:04

+0

请记住,你可能不想为列表“list”命名,因为它是一个内置的python对象。 – Hoopdady 2013-02-13 14:49:17

+0

@Hoopdady是的,谢谢你......我将它列入清单。 – bioinf80 2013-02-13 14:58:50

回答

9

一个简单的发电机会做:

def to_ranges(seq): 
    iseq = iter(seq) 
    x = next(iseq) 
    yield range(0,x+1) 
    start = x 
    for x in iseq: 
     stop = start+x 
     yield range(start+1,stop+1) 
     start = stop 


for x in to_ranges([1,2,3,4]): 
    print x 

这给:

[0, 1]   #0 .. a check 
[2, 3]   #a+1 (2) .. a+b (1+2=3) check 
[4, 5, 6]  #a+b+1 (1+2+1=4) .. a+b+c (1+2+3=6) check 
[7, 8, 9, 10] #a+b+c+1 (1+2+3+1=7) .. a+b+c+d (1+2+3+4=10) check 

终于得到了它的权利。这里不幸的是,第一个循环由于0边界条件是特殊的 - 所以我们只需要展开那个,所有的东西都是对的。

+0

我还没有喝完早上的咖啡,但是这似乎没有产生OP要求的结果。 – DSM 2013-02-13 14:30:17

+0

@DSM - 是的。看我的编辑。 – mgilson 2013-02-13 14:33:04

+0

+1,但还有一个+1缺少'(a * + 1 * ... a + b)'? – root 2013-02-13 14:34:37

0

尽管接受的答案会产生正确的结果,但只需使用几个循环和列表生成器即可获得解决方案。 更高级的语言运算符看起来不合适,因为问题是询问这样一个简单的问题 - 生成一些列表。

此解决方案仅适用于正整数。 带负片的处理序列留给读者练习。

# starting data 
nums = [3, 5, 22, 6] 

# Generate endpoints for output sequences. 
# Note that the first sequence starts specially at 0. 
endpoints = [0] 
for i in range(len(nums)): 
    endpoints.append(endpoints[i] + nums[i]) 
endpoints[0] = -1 

# Generate output sequences. 
outseqs = [] 
for i in range(1, len(endpoints)): 
    outseq = [n for n in range(endpoints[i - 1] + 1, endpoints[i] + 1)] 
    outseqs.append(outseq) 

# Display output sequences. 
for i in range(len(outseqs)): 
    print outseqs[i] 
+0

对于'[1,2,3,4]'作为输入,例如,您的代码会生成[[0],[1,2],[3,4,5],[6,7,8,9 ]]'。相反,它应该是'[[0,1],[2,3],[4,5,6],[7,8,9,10]] – pemistahl 2013-02-13 17:33:40

+0

@PeterStahl固定。 – 2013-02-13 17:36:04

+0

是的,现在它工作。但是,您的解决方案也会因为它不适用于输入中的负数而受到影响。 – pemistahl 2013-02-13 17:50:25

0

所有到目前为止所提供的解决方案,如果是这样,在相反的顺序范围须有输入负数不起作用。我的解决方案涵盖。与Python 2和3的工作在这里:

from itertools import izip 

# create the x (=start) and y (=stop) coordinates for the ranges separately 
def _get_xs(iterable): 
    yield 0 
    for i in xrange(1, len(iterable)): 
     yield sum(iterable[:i]) + 1 

def _get_ys(iterable): 
    yield iterable[0] 
    for i in xrange(1, len(iterable)): 
     yield sum(iterable[:i+1]) 

def to_ranges(iterable): 
    xs = _get_xs(iterable) 
    ys = _get_ys(iterable) 
    for x, y in izip(xs, ys): 
     if x < y: 
      step = 1 
      y += 1 
     elif x > y: 
      step = -1 
      y -= 1 
     else: 
      step = 0 
     try: 
      yield range(x, y, step) 
     except ValueError: 
      yield [x] 

例子:

# edge case: instead of malformed ranges such as range(10, 10), put [10] instead 

>>> list(to_ranges([1, 2, 3, 4])) 
[[0, 1], [2, 3], [4, 5, 6], [7, 8, 9, 10]] 

>>> list(to_ranges([4, 3, 2, 1])) 
[[0, 1, 2, 3, 4], [5, 6, 7], [8, 9], [10]] 

>>> list(to_ranges([4, 3, 2, -1])) 
[[0, 1, 2, 3, 4], [5, 6, 7], [8, 9], [10, 9, 8]] 

>>> list(to_ranges([-4, -3, -2, -1])) 
[[0, -1, -2, -3, -4], [-3, -4, -5, -6, -7], [-6, -7, -8, -9], [-8, -9, -10]] 

>>> list(to_ranges([-1, -2, -3, -4])) 
[[0, -1], [0, -1, -2, -3], [-2, -3, -4, -5, -6], [-5, -6, -7, -8, -9, -10]]