user7422128
user7422128

Reputation: 932

Remove a list while iterating in python without copying to new list

I want to remove elements from my list while iterating the list. I don't think copying the list and performing the operations on either one will solve my problem. I have a nested list, Here as soon as I get the leftmost or the rightmost values of the list == maximum I append it to a new list Lst1 and pop the element from the original list else break from the loop.

lst= [[4, 3, 2, 1, 3, 5]]
lst1=[]
for i in range(len(lst)):
       if lst[0][i]==max(lst[0]):
          lst1.append(lst[0][i])
          lst.remove(lst[0][i])
       elif lst[0][maxsize_lst-1]==max(lst[0]): 
          lst1.append(lst[0][maxsize_lst-1])
          lst.remove(lst[0][maxsize_lst-1])
       else :
          print("NO")
          break;

I'm getting the below errors and sometimes I get index out of range probably because i'm removing the element and iterating the list again

ValueError: list.remove(x): x not in list

The output of list 1 should look something like:

5 4 3 3 2 1

EDIT The final list is coming in the descending order but it's not a sorting problem. Here i will be first picking either the leftmost or rightmost element first and check if it is == max(lst). if any of them follows true i'm removing that element.Now my list would be having one less element. If it was leftmost pop then i would resume from index 1 to last ,vice versa if it was rightmost i would again do the same search from index 0 to maxsize-2 to do the same search. If nothing follows like leftmost or rightmost != Max(lst) then break and print No

Upvotes: 0

Views: 151

Answers (4)

mjmccolgan
mjmccolgan

Reputation: 27

It looks like you're sorting the first list. This can be achieved much more easily. The sorted function will automatically sort it from least to greatest, and then you can use the reversed function to sort greatest to least. Try:

lst1 = reversed(sorted(lst[0]))

EDIT: If you need to use the method put forward in the original code, I caught a mistake in your for loop. You are taking the length of lst, not the sublist, the code should be the following:

for i in range(len(lst[0])):

Also, I don't know if you established a variable maxsize_list, but you can get the last element of the list easily with lst[0][-1]. Finally, your error is being caused by you trying to remove lst[0][-1] from lst, not lst[0]. This is your code without syntax errors. I believe there is a symantic error that occurs when the maximum is at the end.

lst= [[4,3,2,1,3,5]]
lst1=[]
for i in range(len(lst[0])):
    if lst[0][i]==max(lst[0]):
        lst1.append(lst[0][i])
        lst[0].remove(lst[0][i])
    elif lst[0][-1]==max(lst[0]):
        lst1.append(lst[0][-1])
        lst[0].remove(lst[0][-1])
    else :
        print("NO")
        break;

Upvotes: 1

Scott Mermelstein
Scott Mermelstein

Reputation: 15397

@PRMoureu's comment is a big hint to the answer about what's going wrong.

In your sample data, your list is of size 6. You're iterating over the indices, so from 0 through 5. As you progress through your loop, you remove things from your list, but then you continue to look for it. So at some point, you look at lst[0][i] for an i that no longer exists, and that's why you get your error. This will happen as long as you're using the index.

But you don't need the index into the list. You need the value at it. So the recommendation is a very good idea: simply iterate on the list itself, instead of on its indices. This will give you code like this:

lst= [[4, 3, 2, 1, 3, 5]]
lst1=[]
for val in lst[0]:
   print(val)
   if val == max(lst[0]):
      print("a")
      lst1.append(val)
      lst[0].remove(val)
      print(lst[0])
   # this shouldn't even be necessary; you should be able to sort just as well without it
   elif lst[0][-1]==max(lst[0]): 
      print("b")
      lst1.append(lst[0][-1])
      lst[0].remove(lst[0][-1])
   else :
      print("NO")
      break;

Note, python wouldn't use a construct like maxsize_lst. Instead, it would just use lst[0][-1] to get the last element. I fixed the several places where you were referring to lst instead of lst[0], and made your lst definition actually be valid by putting commas between the values.

When I run this code, I get "NO" as a result. Leave the print statements in to understand why. The first time, you have a 4. It isn't the max, so you look to see if the last value is a max. It is, so it gets added. The second time, you have a three, which is again not your max. Nor is the last remaining value (the other 3), so it says "NO" and aborts. You've got the idea by using a break statement, but you need another loop around it that would continue until your list is empty.

To get this to work, you need an outer loop similar to as follows:

lst= [[4, 3, 2, 1, 3, 5]]
lst1=[]
reset = True
while len(lst[0]) != 0 and reset:
    print(lst[0], lst1)
    reset = False
    for val in lst[0]:
       print(val)
       if val == max(lst[0]):
          print("a")
          lst1.append(val)
          lst[0].remove(val)
          reset = True
          break
       elif lst[0][-1]==max(lst[0]): 
          print("b")
          lst1.append(lst[0][-1])
          lst[0].remove(lst[0][-1])
          reset = True
          break
       else :
          print("NO")
          break

Note that I did need to add a break even when popping from the left side. Without that, the end result was that lst1 had a value of [5, 4, 3, 3, 2], and lst[0] still had [1] in it.

Upvotes: 0

Arthur Spoon
Arthur Spoon

Reputation: 462

First of all, you want to remove values from your nested list at the level where they are: lst.remove(x) only searches in lst, not in lst and all possible lists nested in lst. That will solve your problem with ValueError.

Second, simply running your example by hand tells you why it isn't working: you are never updating maxsize_lst, therefore as soon as you pop out an item this value is no longer valid. A simple solution would be to use python's negative indexing system to access the last value of your list: lst[-1]. But even then, if your goal is to get all values in your list sorted, your code cannot do it: on the first step of your example already,

  1. with i=0, you remove 5 from the list (last item, max of values)
  2. next step, i=1, and you will never again access the value at i=0 But then maybe that's not a problem for you, it isn't clear what you want to achieve with your code...

Edit: I re-read your question, if what you want is actually to pop the left/rightmost value when it is a maximum from your old list to your new list, then you shouldn't be iterating over your list with a for loop but rather using a while loop like that:

size_lst = len(lst[0])
while size_lst > 0:
    if lst[0][0] == max(lst[0]):
        # Leftmost element max of the list
        lst1.append(lst[0].pop(0) # Pop leftmost element of lst[0] into lst1
        size_lst -= 1 # Record that you decreased the size of your list
    elif lst[0][-1] == max(lst[0]):
        # Same with the rightmost element
        lst1.append(lst[0].pop(-1)
        size_lst -= 1
    else:
        break

Upvotes: 1

Mike Müller
Mike Müller

Reputation: 85482

There is a much simple solution:

lst = [[4, 3, 2, 1, 3, 5]]
print(sorted(lst[0], reverse=True))

Result:

[5, 4, 3, 3, 2, 1]

Upvotes: 4

Related Questions