Python - 通过列表进行求和和分组

时间:2014-09-09 12:14:19

标签: python sorting

我有一个很大的数字列表如下:

a = [133000, 126000, 123000, 108000, 96700, 96500, 93800, 
 93200, 92100, 90000, 88600, 87000, 84300, 82400, 80700,
 79900, 79000, 78800, 76100, 75000, 15300, 15200, 15100,
 8660, 8640, 8620, 8530, 2590, 2590, 2580, 2550, 2540, 2540, 
 2510, 2510, 1290, 1280, 1280, 1280, 1280, 951, 948, 948,
 947, 946, 945, 609, 602, 600, 599, 592, 592, 592, 591, 583]  

我想要做的是逐个循环查看此列​​表,检查某个值是否高于某个阈值(例如40000)。如果它高于此阈值,我们将该值放在新列表中并忘记它。否则,我们等到值的总和高于阈值,然后我们将值放在列表中,然后继续循环。最后,如果最终值没有达到阈值,我们只需将它们添加到最后一个列表中。

如果我不清楚,请考虑一个简单的例子,阈值为15

[20, 10, 9, 8, 8, 7, 6, 2, 1]

最终列表应如下所示:

[[20], [10, 9], [8, 8], [7, 6, 2, 1]]

我在数学和蟒蛇方面非常糟糕,而且我的智慧结束了。我提出了一些基本代码,但它并没有真正起作用:

def sortthislist(list):
    list = a
    newlist = []
    for i in range(len(list)):
        while sum(list[i]) >= 40000:
            newlist.append(list[i])
    return newlist

任何帮助都将非常感谢。对不起,很长的帖子。

5 个答案:

答案 0 :(得分:1)

下面的函数将接受您的输入列表和一些限制以检查然后输出排序列表:

a = [20, 10, 9, 8, 8, 7, 6, 2, 1]

def func(a, lim):
    out = []
    temp = []
    for i in a:
        if i > lim:
            out.append([i])
        else:
            temp.append(i)
            if sum(temp) > lim:
                out.append(temp)
                temp = []
    return out

print(func(a, 15))
# [[20], [10, 9], [8, 8], [7, 6, 2, 1]]

使用Python,您可以迭代列表本身,而不是迭代它的索引,因此您可以看到我使用for i in a而不是for i in range(len(a))

在函数out中是您希望在结尾返回的列表; temp是一个临时列表,其中填充了数字,直到temp的总和超过lim值,此时此temp会附加到out并替换为空列表。

答案 1 :(得分:0)

def group(L, threshold):
    answer = []
    start = 0
    sofar = L[0]
    for i,num in enumerate(L[1:],1):
        if sofar >= threshold:
            answer.append(L[start:i])
            sofar = L[i]
            start = i
        else:
            sofar += L[i]
    if i<len(L) and sofar>=threshold:
        answer.append(L[i:])
    return answer

输出:

In [4]: group([20, 10, 9, 8, 8, 7, 6, 2, 1], 15)
Out[4]: [[20], [10, 9], [8, 8], [7, 6, 2]]

答案 2 :(得分:0)

希望这会有所帮助:)

vlist = [20, 10,3,9, 7,6,5,4]

thresold = 15

result = []
tmp = []
for v in vlist:
    if v > thresold:
        tmp.append(v)
        result.append(tmp)
        tmp = []
    elif sum(tmp) + v > thresold:
        tmp.append(v)
        result.append(tmp)
        tmp = []
    else:
        tmp.append(v)

if tmp != []:
    result.append(tmp)

结果如下:

[[20], [10, 3, 9], [7, 6, 5], [4]]

答案 3 :(得分:0)

这是另一种方式:

def group_by_sum(a, lim):
    out = []
    group = None
    for i in a:
        if group is None:
            group = []
            out.append(group)

        group.append(i)

        if sum(group) > lim:
            group = None
    return out

print(group_by_sum(a, 15))

答案 4 :(得分:0)

我们已经有了很多工作答案,但这里还有另外两种方法。

我们可以使用itertools.groupby收集这些组,给定一个了解组内容的有状态累加器。我们最终得到一组(密钥,组)对,因此一些额外的过滤只能让我们获得组。此外,由于itertools提供了迭代器,我们将它们转换为列表进行打印。

from itertools import groupby

class Thresholder:
  def __init__(self, threshold):
    self.threshold=threshold
    self.sum=0
    self.group=0
  def __call__(self, value):
    if self.sum>self.threshold:
      self.sum=value
      self.group+=1
    else:
      self.sum+=value
    return self.group
print [list(g) for k,g in groupby([20, 10, 9, 8, 8, 7, 6, 2, 1], Thresholder(15))]

该操作也可以作为单个reduce调用完成:

def accumulator(result, value):
  last=result[-1]
  if sum(last)>threshold:
    result.append([value])
  else:
    last.append(value)
  return result
threshold=15
print reduce(accumulator, [20, 10, 9, 8, 8, 7, 6, 2, 1], [[]])

由于重复调用sum(),此版本很难扩展到许多值,并且阈值的全局变量相当笨拙。此外,将其调用为空列表仍将留下一个空组。

编辑:问题逻辑要求将高于阈值的值放入他们自己的组中(不与收集的较小值共享)。在编写这些版本时我没有想到这一点,但Ffisegydd接受的答案处理了它。如果输入数据按降序排序,则没有有效差异,因为所有样本数据都显示为。