1
w = [1, 2, 3, -3, -2, 4, -4, 1, 2, -2]


def data_remover(xarray, ind):
    for i in ind:
        del xarray[i]
    return xarray


print(data_remover(w, [2, 3, 5, 6, 8, 9]))

I am trying to write a code such that it removes adjacent (+n, -n) pairs such as (3,-3) (4,-4) etc.

However I cannot use del[i] since when I remove an element the xarray also changes. I tried to use deepcopy to copy the x array but I couldnt manage to run the code.

from copy import deepcopy

w = [1, 2, 3, -3, -2, 4, -4, 1, 2, -2]


def data_remover(xarray, ind):
    xcopy = deepcopy(xarray)
    for i in ind:
        del xarray[i]
    return xarray


print(data_remover(w, [2, 3]))
Arman Çam
  • 115
  • 7
  • 1
    If you are reading from left to right, if you delete +n at position i, then -n will automatically be there at position i. just perform two delete calls at i. – Niteya Shah Jan 14 '21 at 10:36
  • 1
    Did you try getting a copy before the data_remover function? Like `temp = w`, then `data_remover(temp, [2, 3])`? – anvoice Jan 14 '21 at 10:38
  • 1
    Does this answer your question? [How to remove items from a list while iterating?](https://stackoverflow.com/questions/1207406/how-to-remove-items-from-a-list-while-iterating) – Tomerikoo Jan 14 '21 at 10:40
  • @anvoice with Python doing `temp = w` doesn't achieve nothing at all... You just get another reference to the same list object... – Tomerikoo Jan 14 '21 at 10:52
  • meant that as temp = w[:]... Need to get some sleep. – anvoice Jan 14 '21 at 10:54

4 Answers4

2

There are two ways I can think of

Assuming the list of indices to remove is sorted Either set a variable to keep track of deletions

def data_remover(xarray, ind):
    removed_count = 0
    for i in ind:
        del xarray[i - removed_count]
        removed_count +=1
    return xarray

Or create a new list

def data_remover(xarray, ind):
    return [item for i, item in enumerate(xarray) if i not in ind]

Ron Serruya
  • 3,988
  • 1
  • 16
  • 26
1

You can sort the list of indices in descending order so that deleting an element will not effect the position of another. You can do this by reversed(ind)

w = [1, 2, 3, -3, -2, 4, -4, 1, 2, -2] 
def data_remover(xarray, ind):
    for i in reversed(ind):
         del xarray[i] 
    return xarray 
print(data_remover(w, [2, 3, 5, 6, 8, 9]))

Or if your indices are not in any order you can always sort them in descending order.

for i in sorted(ind, reverse = True):
Shadowcoder
  • 962
  • 1
  • 6
  • 18
  • very clever solution – Arman Çam Jan 14 '21 at 10:44
  • this is really spicy, but if you're planning for other people to read your code, please go with Ron's answer – ddg Jan 14 '21 at 10:49
  • @ddg why? And I hope you mean his second suggestion... – Tomerikoo Jan 14 '21 at 10:50
  • 1
    It's just late at night and I'm being dramatic. When I'm scanning the function, the notable words are "for" "reversed" "del". The usage of "reversed" feels like a red herring, because it has no conceptual relation to the problem and only exists to step around an implementation detail. As someone reading code, it takes me about 3x longer to parse than a simple list comprehension. – ddg Jan 14 '21 at 11:04
  • 1
    @ddg That is indeed a very good point! I agree – Tomerikoo Jan 14 '21 at 11:56
1

The question How to remove items from a list while iterating? already has many solutions for this problem. In your case, the simplest solution will be to iterate the indexes from the end, that way you're not affecting the next deletions and the indexes stay correct in all iterations. So just change the loop to:

for i in ind[::-1]:

Example run:

def data_remover(xarray, ind):
    print(xarray)
    for i in ind[::-1]:
        print(f"deleting {xarray[i]} from index {i},", end='')
        del xarray[i]
        print(f" gives - {xarray}")
    return xarray

print(data_remover([1, 2, 3, -3, -2, 4, -4, 1, 2, -2], [2, 3, 5, 6, 8, 9]))

Gives:

Initial -                         [1, 2, 3, -3, -2, 4, -4, 1, 2, -2]
deleting -2 from index 9, gives - [1, 2, 3, -3, -2, 4, -4, 1, 2]
deleting  2 from index 8, gives - [1, 2, 3, -3, -2, 4, -4, 1]
deleting -4 from index 6, gives - [1, 2, 3, -3, -2, 4, 1]
deleting  4 from index 5, gives - [1, 2, 3, -3, -2, 1]
deleting -3 from index 3, gives - [1, 2, 3, -2, 1]
deleting  3 from index 2, gives - [1, 2, -2, 1]
Final -                           [1, 2, -2, 1]
Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
0

You can sidestep having to remove at multiple indices. To remove adjacent inverses (3, -3) in one pass, I would do something like:

data = [1, 2, 3, -3, -2, 4, -4, 1, 2, -2]

location = 0  # start at 0
temp = []  # new array that you're building

while location < len(data):
    if data[location] == -data[location+1]:
        location += 2  # inverses, skip them!
    else:
        temp.append(data[location])
        location += 1

data = temp
ddg
  • 1,090
  • 1
  • 6
  • 17