动态拆分列表,使用范围和值进行拆分

时间:2014-06-26 18:00:01

标签: python list math numpy

我想将值拆分为提供的吐痰数量。例如,如果我有value = 165340split = 5然后列表应该变为['0-33068', '33069-66137', '66138-99204', '99205-132272', '132273-165340'] ...

到目前为止,我刚刚想出了类似的东西,但这不是动态的...... 所以我想如何建立一个字符串列表,比如用差异val/split

分割的数字
for i in range(split):
    if i==0:
        lst.append('%s-%s' % (i, val/split))
    elif i==1:
        lst.append('%s-%s' % (val/split+i, val/split*2+1))
    elif i == 2:
        lst.append('%s-%s' % (val/split*i+2, val/split*3))
    elif i == 3:
        lst.append('%s-%s' % (val/split*i+1, val/split*4))
    elif i == 4:
        lst.append('%s-%s' % (val/split*i+1, val/split*5))
    else:
        pass

3 个答案:

答案 0 :(得分:1)

FINAL:

我在这里做了很多尝试,特别是在使用remainder = value % numsplits,然后使用int(i * remainder // numsplits)尝试保持紧密。但最终,我不得不放弃并回到浮点,这似乎给出了最接近的结果。通常的浮点问题适用。

def segment(value, numsplits):
    return ["{}-{}".format(
        int(round(1 + i * value/(numsplits*1.0),0)),
        int(round(1 + i * value/(numsplits*1.0) +
              value/(numsplits*1.0)-1, 0))) for
        i in range(numsplits)]

>>> segment(165340, 5)
['1-33068', '33069-66136', '66137-99204', '99205-132272', '132273-165340']
>>> segment(7, 4)
['1-2', '3-4', '4-5', '6-7']

我不会发现这个问题存在很大问题。我确实从1开始而不是0,但没有必要(将int(round(1 + i * ...更改为int(round(i * ...以更改)。旧结果如下。

value = 165340
numsplits = 5
result = ["{}-{}".format(i + value//numsplits*i, i + value//numsplits*i + value//numsplits) for i in range(numsplits)]

可能值得投入一个功能

def segment(value,numsplits):
    return ["{}-{}".format(value*i//numsplits, 1 + value//numsplits*i + value//numsplits) for i in range(numsplits)]

以下内容将以您的值

进行切换
def segment(value, numsplits):
    return ["{}-{}".format(max(0,i + value*i//numsplits), min(value,i + value*i//numsplits + value//numsplits)) for i in range(numsplits)]

答案 1 :(得分:1)

要回答这个问题,确切知道我们应该如何对待0这一点非常重要 - 但看起来你并没有问过自己这个问题。示例输出中的间隔不一致;你在第一个时间间隔内以0开头,而前两个时间间隔都有33,069个元素(计算0),但你也在{{{ 1}}。 如果1653400都计入元素数量,则165340 可分为五个偶数间隔。 < / p>

以下是一些可能有助于您了解问题的不同解决方案。

偶数间隔,从零开始计算

让我们假设你确实想要165340和&#34; top&#34;值计为元素并显示在结果中。换句话说,值11实际上表示以下12个元素范围:

0

并均匀分为以下非负间隔:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

如果我们只关注可均分的情况,我们可以使用相当短的函数(注意:这些解决方案适用于Python 3.x,或适用于带有['0-3', '4-7', '8-11'] 的Python 2.x) :

from __future__ import division

然而,这个函数通过删除一些数字来处理>>> def evenintervals(value, n): ... binsize = (value + 1) // n ... intervals = ((x * binsize, (x + 1) * binsize - 1) for x in range(n)) ... return ['{}-{}'.format(x, y) for x, y in intervals] ... >>> evenintervals(11, 3) ['0-3', '4-7', '8-11'] >>> evenintervals(17, 2) ['0-8', '9-17'] (以及任何其他不可均匀分割的情况):

165340

从纯粹的数学角度来看,这是行不通的。但是,如果由于某种原因你想要显示 >>> evenintervals(165340, 5) ['0-33067', '33068-66135', '66136-99203', '99204-132271', '132272-165339'] ,我们可以稍微捏一下,但实际上不计算它是一个第一个区间的元素。

偶数间隔,从一个

开始计算

此处&#39;是一个不会将0计为列表元素的函数,但是 可以让您选择显示它,如果你&#39;只是那个zany:

0

在您的问题中,此版本的函数可能与您要求的内容最接近,即使它没有显示您在示例输出中给出的确切值:

>>> def evenintervals1(value, n, show_zero=False):
...     binsize = value // n
...     intervals = [[x * binsize + 1, (x + 1) * binsize] for x in range(n)]
...     if show_zero:
...         intervals[0][0] = 0
...     return ['{}-{}'.format(x, y) for x, y in intervals]
... 
>>> evenintervals1(20, 4)
['1-5', '6-10', '11-15', '16-20']
>>> evenintervals1(20, 5, show_zero=True)
['0-5', '6-10', '11-15', '16-20']

但我们仍然存在输入不能均匀分割的问题。如果我们想要一个更通用的解决方案怎么办?

不均匀的间隔

让我们考虑如何处理更广泛的投入。我们应该能够从任何正整数>>> evenintervals1(165340, 5, show_zero=True) ['0-33068', '33069-66136', '66137-99204', '99205-132272', '132273-165340'] 生成从n1非重叠的正整数范围。换句话说,如果我们的整数是n,我们希望能够生成一个包含多达五个范围的列表。但是我们应该如何分发&#34;额外&#34;元素,以使范围尽可能均匀?

我们可能不想随意分发它们。我们可以延长或缩短列表中的最后一个范围,但这有可能是非常不平衡的:

5

在前一种情况下,最后一个元素比其他元素大100%,在后一种情况下,它的小33%。如果您将非常大的值拆分为更少的间隔,这可能不是一个问题。

更有可能的是,我们想要一个能够产生最均匀范围的函数。我将通过在# 40 split 7 times, adding remainder to last item ['1-5', '6-10', '11-15', '16-20', '21-25', '26-30', '31-40'] # 40 split 7 times, subtracting excess from last item ['1-6', '7-12', '13-18', '19-24', '25-30', '31-36', '37-40'] 的一点帮助下将该部分的其余部分分散到列表的第一个元素中来实现此目的:

itertools

最后,使用OP中给出的示例输入:

>>> from itertools import zip_longest  # izip_longest for Python 2.7
>>> def anyintervals(value, n):
...     binsize, extras = value // n, value % n
...     intervals = []
...     lower = 0
...     upper = 0
...     for newbinsize in map(sum, zip_longest([binsize] * n, [1] * extras, fillvalue=0)):
...         lower, upper = upper + 1, upper + newbinsize
...         intervals.append((lower, upper))
...     return ['{}-{}'.format(x, y) for x, y in intervals]
... 
>>> anyintervals(11, 3)
['1-4', '5-8', '9-11']
>>> anyintervals(17, 2)
['1-9', 10-17']

如果显示从零开始的第一个间隔非常重要,我们可以应用>>> anyintervals(165340, 5) ['1-33068', '33069-66136', '66137-99204', '99205-132272', '132273-165340'] 中使用的相同逻辑来修改evenintervals1中的第一个整数,然后再返回或写入与此类似的函数开始计数为零。

我确实实现了另一个分发&#34; extras&#34;在最后的范围而不是第一个范围中,当然还有很多其他的实现,你可能有兴趣摆弄,但这些解决方案留给读者练习。 ;)

答案 2 :(得分:0)

使用numpy的一种可能性:

from numpy import arange
v = 165340
s = 5
splits = arange(s + 1) * (v / s)
lst = ['%d-%d' % (splits[idx], splits[idx+1]) for idx in range(s)]
print '\n'.join(lst)

输出:

0-33068
33068-66136
66136-99204
99204-132272
132272-165340