如何在Python中有条件地对列表元素进行求和?

3

我有

一堆从0到大约1000的整数列表,以下是这样一个列表的前几个元素:

oldlist = [216, 216, 199, 253, 271, 217, 183, 225, 199, 217, 217, 235, 254, 217, 235, 235, 234, 234, 235, 231, 183, 263, 298, 190, 248, 200, 223, 199, 225, 195, 240]

我想要

将连续的列表元素相加,并且这些元素>215,将它们合并为单个列表元素,同时保留列表的其余部分。 对于上面的列表,结果应为:

newlist = [432, 199, 741, 183, 225, 199, 2544, 183, 561, 190, 248, 200, 223, 199, 225, 195, 240]

我尝试过

def dtadder(oldlist):
    newlist = []
    nlidx = 0  # newlist index
    for idx, x in enumerate(oldlist):
        if idx > 0 and oldlist[idx - 1] > 215 and oldlist[idx] > 215:
            x = oldlist[idx] + newlist[nlidx - 1]
            newlist.remove(newlist[nlidx - 1])
            nlidx -= 1
        newlist.append(x)
        nlidx += 1
    return newlist

发生了什么

问题在于所有事情都按照我预期的方式进行,直到循环的第116次迭代(nlidx=85),突然某些原因导致列表中删除了newlist[4]=225。虽然我还没有搞清楚何时以及为什么会这样做,但其他元素也会偶尔发生这种情况。似乎只有大于215的元素会被删除。

我错过了什么?虽然我对编程和Python还比较新手,但我觉得应该有一种更简单和更易读的方法来解决这个问题。除了解决我的问题之外,我也很想了解为什么我的解决方案不起作用。

4个回答

4

您可以尝试使用itertools.groupby

from itertools import groupby

out = []
for v, g in groupby(oldlist, lambda x: x > 215):
    if v:
        out.append(sum(g))
    else:
        out.extend(g)

print(out)

注意:你的代码不起作用,因为 list.remove 只会移除第一个匹配到的值,这可能不是你想要的。

1
你也可以像你所做的那样遍历列表,但无需担心每个项目的索引:
oldlist = [216, 216, 199, 253, 271, 217, 183, 225, 199, 217, 217, 235, 254, 217, 235, 235, 234, 234, 235, 231, 183, 263, 298, 190, 248, 200, 223, 199, 225, 195, 240]

def get_nums_more_than_250():
    temp_nums_to_add = 0
    new_list = []
    for i in oldlist:
        if i >215:
            temp_nums_to_add += i #add numbers togther 
        else:
            if temp_nums_to_add !=0:
                new_list.append(temp_nums_to_add)
                temp_nums_to_add = 0
            new_list.append(i)
    
    #for final iteration (if values are stored in temp_nums_to_add
    if temp_nums_to_add !=0:
        new_list.append(temp_nums_to_add)
    return new_list
    
print(get_nums_more_than_250())

尽管这不像其他解决方案那样简洁,但我认为仍然应该展示我的方式。

退出循环后,您需要检查temp_nums_to_add。此外,如果i < 215,则始终要添加i。 - Kenny Ostrom
尝试使用以下输入进行调试:[1, 1, 300, 300, 1, 1, 250, 250, 250] - Kenny Ostrom
@KennyOstrom 谢谢,我已经做出了更改,并且没有发现任何错误,所以我认为现在应该已经解决了。根据您给我的列表,我得到了[1, 1, 600, 1, 1, 750](正确)。 - J_cyber

0
您可以遍历所有数字,您对新数字的反应取决于您上一个数字。因此,您将有两种状态:(上一个数字较小)和(上一个数字较大),根据状态,您会相应地对待新数字。
class State:
    SMALLER = 101
    BIGGER = 102
def dtadder(old):
    new = []
    state = State.SMALLER
    tmp_sum = 0
    
    for number in old:
        match state:
            case State.SMALLER:
                if number <= 215:
                    new.append(number)
                else:
                    tmp_sum = number
                    state = State.BIGGER
            case State.BIGGER:
                if number <= 215:
                    new.append(tmp_sum)
                    tmp_sum = 0
                    new.append(number)
                    state = State.SMALLER
                else:
                    tmp_sum += number
    return new

0

一个变种的Andrej提出的方法, 允许它缩减为列表解析(通过去除appendextend之间的条件选择):

from itertools import groupby

newlist = [sum(grp) for _, grp in groupby(oldlist, key=lambda x: x > 215 or object())]

基本上,关键函数返回 True(对于超过 215 的值,它们都会聚集在一起),或保证不等于任何其他对象的唯一对象(对于值 <= 215),因此它们总是作为一个仅包含一个对象的组而聚合。 因此,您可以无条件地 sum 所有组,而不必区别处理不同类型的组。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接