-2

Suppose that I have a list that has [0, 1, 2, 3 , 4, 5, 6] in it. I want to remove those elements that are greater than or equal to 3 and add those removed elements to the beginning of the list. So I wrote the code below:

list = [0, 1, 2, 3, 4, 5, 6]
new_list =[]

for number in list:
    if number >= 3:
        dropped_number = list.pop()
        new_list.append(dropped_number)
    new_list.sort()

new_list += list

print(new_list)

However, when I ran the code, the result was displayed as [5, 6, 0, 1, 2, 3 , 4]. Could anyone please explain to me at which step I did wrong here?

  • 2
    also print out "dropped_number" as I don't think pop is doing what you think it is doing. – Kenny Ostrom Sep 02 '21 at 22:18
  • Do you want the items that have been deleted to start at the beginning of the list or to the last? – hf wassim Sep 02 '21 at 22:18
  • 3
    This was briefly closed as a duplicate of "modifying the list you are iterating over" and that was part of your problem, but not all of it. – Kenny Ostrom Sep 02 '21 at 22:27
  • 2
    Can you include your expected result in your question to avoid confusion? `append` usually means *add to the end*. And there are at least two options for prepending: `[3,4,5,6,0,1,2]` or `[6,5,4,3,0,1,2]` – Michael Szczesny Sep 02 '21 at 22:31
  • 1
    @KennyOstrom I dupe-hammered it, then undid that because I figured I had misread the code. However, my original reasoning still applies, on a more careful review. – Karl Knechtel Sep 02 '21 at 22:52
  • @MichaelSzczesny OP clearly says "add to the beginning of the list". The reason `.append` is used in the code is that OP is intends to append to a *separate* list and then put the rest of the elements after that. – Karl Knechtel Sep 02 '21 at 22:53
  • 1
    Please edit the question to limit it to a specific problem with enough detail to identify an adequate answer. – Community Sep 06 '21 at 15:56

3 Answers3

6

There are two issues with your code.

  1. the number you obtain with list.pop() is not the one you just checked with your condition (it is merely the last one in the list)
  • When you reach 3, list.pop() removes 6,
  • When you reach 4, list.pop() removes 5,
  • You never reach 5 because you're at the end of what remains of the list at that point.
  1. removing items from a list within a for-loop on the same list will cause the for-loop to skip items or complain that the list changed during iterations. So, even if you were to pop the appropriate number, your loop would miss items.

You also don't need to sort new_list every time you add to it, you can do it once at the end, but that just optimization.

Instead of a for-loop, you could use the sort method with a key parameter that returns a boolean indicating True for elements that do not meet your conditions (i.e that will be shifted to the right). Because Python's sort is stable, this will only place elements in two groups without otherwise changing their relative order.

L = [0, 2, 4, 6, 1, 3, 5]
L.sort(key=lambda x: not x>=3)
print(L) # [4, 6, 3, 5, 0, 2, 1]

If you need a more procedural solution, you can separate the values in two lists that you stick together at the end:

L = [0, 2, 4, 6, 1, 3, 5]
left,right = [], []
for x in L:
    if x >= 3: left.append(x)
    else:      right.append(x)
L = left + right

# [4, 6, 3, 5, 0, 2, 1]
Alain T.
  • 40,517
  • 4
  • 31
  • 51
2

Modifying a list while iterating over it is usually problematic. What if instead you thought of the problem as building a new list out of two subsets of the original list?

>>> old_list = list(range(7))
>>> [i for i in old_list if i >= 3] + [i for i in old_list if i < 3]
[3, 4, 5, 6, 0, 1, 2]
Samwise
  • 68,105
  • 3
  • 30
  • 44
-1

The reason your program doesn't work is because you are modifying the list whilst searching through it. Instead, you can start by adding the elements >= 3 to a new list and then separately appending the elements < 3 to the list. Also, considering you are created a second 'new_list', there is no need to remove the elements from the first list.

Your new code:

list = [0, 1, 2, 3, 4, 5, 6]
new_list = []

# Append numbers greater than 3 to the new list
for number in list:
    if number >= 3:
        new_list.append(number)

# Append the numbers less than 3 to the new list
new_list += list[0:list.index(new_list[0])]

print(new_list)

Just to note, this method takes a section of the original list from position 0, to the position (.index) of the first item in the new list, which automatically generates the < 3 condition as the first item in the new list corresponds to the items before the >= 3 condition is met.

list[0:list.index(new_list[0])]
  • 1
    I don't know if we can assume, from the question, that the input list will always be in ascending order. – CrazyChucky Sep 02 '21 at 22:53
  • The question was primarily addressing why the program wasn't working with that given input. If you required the list to be ordered, you could simply sort it first with: list.sort(). – Happy Avocado Sep 12 '21 at 01:16