简体   繁体   English

如何有条件地对 python 中的列表元素求和?

[英]How to conditionally sum elements of a list in python?

I have我有

a bunch of lists of integers from 0 to somewhere around 1000, here are the first elements of such a list:一堆从 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]

I want我想

to add consecutive list elements that are >215 and merge them into a single list element, leaving the rest of the list as it is.添加大于 215 的连续列表元素并将它们合并为单个列表元素,使列表的 rest 保持原样。 For the above list it should result in:对于上面的列表,它应该导致:

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

I tried我试过了

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

What happened发生了什么

is that everything works out exactly how I expect it to, until the 116th iteration of the loop (nlidx=85), when for some reason newlist[4]= 225 is removed from the list.是一切都按照我的预期进行,直到循环的第 116 次迭代 (nlidx=85),由于某种原因 newlist[4]= 225 从列表中删除。 This keeps occasionally happening with other elements though I haven't figured out when and why.尽管我还没有弄清楚何时以及为什么,但这偶尔会发生在其他元素上。 It seems that only elements >215 are removed.似乎只删除了 >215 的元素。

What am I missing here?我在这里想念什么? I'm fairly new to programming and python but I feel there should be an easier and more readable way to do this.我对编程和 python 相当陌生,但我觉得应该有一种更简单、更易读的方法来做到这一点。 Apart from a solution to my problem I would be really interested in understanding why my solution doesn't work.除了解决我的问题之外,我真的很想了解为什么我的解决方案不起作用。

You can try itertools.groupby :您可以尝试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)

Note: your code doesnt work, because list.remove removes first occurence of the value.注意:您的代码不起作用,因为list.remove删除了该值的第一次出现。 This is probably not what you want.这可能不是你想要的。

You could also iterate through the list like you have done but without having to worry about the index of every item:您还可以像以前一样遍历列表,但不必担心每个项目的索引:

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())

Although this isn't as sleek as the other solutions I thought I should still show mine.虽然这不像其他解决方案那样时尚,但我认为我仍然应该展示我的解决方案。

You could go through all numbers, and your reaction to the new number depends on the last number you had.您可以通过所有数字 go ,您对新数字的反应取决于您拥有的最后一个数字。 So you will have two states: (last number was small) and (last number was big), and depending on the state, you react to the new number accordingly.因此,您将有两种状态:(最后一个数字很小)和(最后一个数字很大),并且根据 state,您会对新数字做出相应的反应。

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

A variant on what Andrej came up with that allows it to reduce to a listcomp (by removing the conditional choice between append and extend ): Andrej 提出的一个变体允许它减少到 listcomp(通过删除appendextend之间的条件选择):

from itertools import groupby

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

Basically, the key function returns either True (for values above 215, which all group together) or a guaranteed unique object that will not be equal to any other object (for values <= 215 ) so they always group as a group of just one object.基本上,键 function 返回True (对于高于 215 的值,它们全部组合在一起)或保证唯一的 object 不等于任何其他 object,因此它们总是分组为<= 215 group of 21C4B666Z object。 Thus, you can unconditionally sum all groups, rather than treating different types of groups differently.因此,您可以无条件地对所有sum ,而不是对不同类型的组进行不同的处理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM