-1

I have an array that I would like to iterate over and modify the array itself, through inserts or deletions.

for idx, ele in enumerate(np.nditer(array)):
  if idx + 1 < array.shape[0] and ele > array[idx+1]:
    array = np.delete(array, idx+1)
  print(ele)

Given [5, 4, 3, 2, 1] I want the loop to print out 5 3 1 because 4 and 2 are smaller than their previous elements. But because python creates an iterator based on the first instance of array so it prints 5 4 3 2 1. I want to know if I can get

Generally speaking I want the iterator to be modified if I modify the array within the body of my loop.

vnal
  • 53
  • 7
  • Usually objects such as function, classes.. used from the standard library, or other third-party library should behave as the docs says. So you do not have to check their behavior in your code. – adnanmuttaleb Nov 03 '19 at 14:30
  • But you may mean something else, so please add more details to your question if so. – adnanmuttaleb Nov 03 '19 at 14:31
  • Your loop seems to do what you want - at least for that input. It isn't clear what you are asking. – wwii Nov 03 '19 at 14:33
  • I've added some more information. Is it clearer? – vnal Nov 03 '19 at 14:45
  • If you are changing `array` along the way, it may be better to use a `while` loop rather than `for`. And avoid `nditer` unless you really need some special feature. – hpaulj Nov 03 '19 at 14:48
  • @hpaulj Will while loops reevaluate the loop condition on every iteration? – vnal Nov 03 '19 at 14:53
  • 2
    "python creates iterable object by evaluating the array the first time." "the loop reevaluate the object" - sorry, this is word salad to me. We need an example with initial array, expected output and actual output. – actual_panda Nov 03 '19 at 15:16
  • You can try: https://stackoverflow.com/a/6022811/11610186 – Grzegorz Skibinski Nov 03 '19 at 15:21
  • @actual_panda I removed the example I had before because all the answers were trying to solve the example rather than the general problem. I added it back. – vnal Nov 03 '19 at 15:24
  • 1
    @actual_panda. Thanks for the term "word salad". – Mad Physicist Nov 03 '19 at 15:25
  • @GrzegorzSkibinski but iterating over the original will not reflect changes I make in the copy which is what I want. – vnal Nov 03 '19 at 15:27
  • The final array when running your new code is `array([1, 2, 4, 5])`. If you don't want `ele` to print if `ele == 3`, use an `else` block? https://pastebin.com/17zvAWaA – actual_panda Nov 03 '19 at 15:29
  • @actual_panda I'm not referring to this specific example. As many others have pointed out and as I mentioned in edits to my post I could solve this specific problem by using boolean indexing. Generally speaking, if I change an array I am iterating over during the loop, I want following iterations of my array to reflect that change. – vnal Nov 03 '19 at 15:32
  • @vnal That's how it's working already. – actual_panda Nov 03 '19 at 15:33
  • @actual_panda I'm not talking about the output array. I'm talking about the print output. – vnal Nov 03 '19 at 15:34
  • This has nothing to do with how Python builds iterators then. You assign `ele = 3`. Then you `print(ele)`. There is no way to make it print something else without reassigning the name. – actual_panda Nov 03 '19 at 15:35
  • @actual_panda Pretend it's a linked list or something. Honestly the specifics of "ele is already assigned a value" aren't really important here because this specific example isn't as complex as the actual problem I'm dealing with. I just want to know if there is a way to change a data structure I'm iterating over in a for loop and have that change be reflected in later iterations of that same for loop. – vnal Nov 03 '19 at 15:39
  • Again, that's already how iteration works in Python. You can mutate the object you are iterating over in the loop body, and that mutation will apply to future iterations. – actual_panda Nov 03 '19 at 15:41
  • (Note that in your example, you are not mutating anything. `np.delete` returns a new array. Then you rebind the name `array` to the return value.) – actual_panda Nov 03 '19 at 15:47
  • @actual_panda If that's how iterators work then that's what I want to do. I want to modify the same array but I can only find ways to delete and assign to a copy. I just posted another example. – vnal Nov 03 '19 at 15:51

2 Answers2

2

You cannot mutate the length of a numpy array, because numpy assigns the required memory for an array upon its creation.

With

array = np.delete(array, idx+1)

You are creating a new array on the right hand side of the = and reassign the name array.

The return value for enumerate(np.nditer(array)) has already been created at that point and won't recognize that the name array has been rebound.

In principle, you can iterate over a sequence and mutate its length at the same time (generally not a good idea). The object just needs to have methods that let you mutate its length (like lists, for example).

Consider:

>>> l = [5, 4, 3, 2, 1]                                                         
>>> for idx, ele in enumerate(l): 
...:     if ele == 3: 
...:         l.pop(idx) # mutates l 
...:     print(ele) 
...:                                                                            
5
4
3
1
>>> l                                                                           
[5, 4, 2, 1]

Notice that

  1. l is mutated.
  2. The loop does not print 2 because popping an element reduces the indexes of all the remaining elements by one. Now l[2] == 2, but index 2 has already been visited by the iterator, so the next print-call prints l[3] which is 1.

This proves that mutations to l have effect on subsequent iterations.

actual_panda
  • 1,178
  • 9
  • 27
0

Instead of looping over an array, you can use where method to find indices of elements meeting some condition.

Then to delete the selected element (or elements), you can use delete method, passing the source array, and a list of indices. Then save the result, e.g. under the same variable.

To add an element, you can use append or insert methods (for details see Numpy documentation).

I have also found a SO post concerning how to loop and delete over an array. See Deleting elements from numpy array with iteration

Valdi_Bo
  • 30,023
  • 4
  • 23
  • 41