3

I have

a bunch of lists of integers from 0 to somewhere around 1000, here are the first elements of such a list:

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. 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. This keeps occasionally happening with other elements though I haven't figured out when and why. It seems that only elements >215 are removed.

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. Apart from a solution to my problem I would be really interested in understanding why my solution doesn't work.

0

4 Answers 4

4

You can try 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. This is probably not what you want.

Sign up to request clarification or add additional context in comments.

Comments

1

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.

3 Comments

You'll need to check temp_nums_to_add after you exit the loop. Also you always want to add i if i < 215.
Try this input for debugging: [1, 1, 300, 300, 1, 1, 250, 250, 250]
@KennyOstrom thanks, I have made the changes and can't find any bugs with it so I think is should be sorted now. With the list you gave me I get [1, 1, 600, 1, 1, 750] (correct).
0

You could go through all numbers, and your reaction to the new number depends on the last number you had. 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.

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

Comments

0

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

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. Thus, you can unconditionally sum all groups, rather than treating different types of groups differently.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.