-2
lst = ['apple', 'orange', 'kiwi', 'ananas',
       'tea', 'coffee', 'milk', 'love', 'peace']

for i in range(len(lst)):
    if (i + 1) % 2 == 0:
        lst.append(lst[i])
        lst.pop(i)

Basically here I want the items with even index to be added at the end of this list it works for the second item but still doesn’t for the rest of them

Alex Reinking
  • 16,724
  • 5
  • 52
  • 86
RECUR
  • 21
  • 5
  • 1
    hint: when you pop an element from the middle of a list, what happens to the rest of them? – Adam.Er8 May 17 '22 at 06:44
  • I can't post an answer, but get items with the even index before you start moving the list around. Then move them to the end after you have each item – Freddy Mcloughlan May 17 '22 at 06:46
  • the other element change index – RECUR May 17 '22 at 06:46
  • i really appreciate your help guys , i was trying to pop it out and append it to the end of the list – RECUR May 17 '22 at 06:47
  • @FreddyMcloughlan , do you mean extract the in a new list ? – RECUR May 17 '22 at 06:49
  • Bingo, the elements' index changes. So either account for that when you calculate the next index, or start with the largest index instead of the lowest one. – Aran-Fey May 17 '22 at 06:49
  • @closers: did you notice that the provided code does not iterate the list? Current code is indeed wrong, and the advices found in the proposed duplicate are relevant for the problem, but not for the code... – Serge Ballesta May 17 '22 at 06:50
  • @blhsing I'm not a big fan of that duplicate, especially since there's a valid solution iterating from 1 to half of the list's length, appending and popping along the way. – Robby Cornelissen May 17 '22 at 06:53
  • @Aran-Fey i cant find way or pattern to calculate the next changed index, can u please help ? – RECUR May 17 '22 at 06:53
  • i really couldn’t t find a way – RECUR May 17 '22 at 06:55
  • I strongly suggest reading the official python tutorial's chapter on `for`-loops: https://docs.python.org/3/tutorial/controlflow.html#for-statements ; one of the very first thing mentioned is: ***Code that modifies a collection while iterating over that same collection can be tricky to get right. Instead, it is usually more straight-forward to loop over a copy of the collection or to create a new collection:***. And then it gives examples of how to do these two approaches. Do not use `lst.append` or `lst.pop` inside the `for`-loop that iterates over `lst`! – Stef May 17 '22 at 07:56

3 Answers3

3

You can use Python's wider-step ranges:

lst = lst[1::2] + lst[0::2]

The right hand side of the plus says "grab every 2nd element starting from the first" and the left hand side says "grab every 2nd element starting from the second". This basically reconstructs the list with the odd elements first and the even elements last.

It even avoids expensive pops that make your reference algorithm O(n^2)

Alex Reinking
  • 16,724
  • 5
  • 52
  • 86
  • thank u bro , but i wanted to work in in place withe that list , using pop and insert or append – RECUR May 17 '22 at 07:55
1

The problem with your approach is that the elements shift after you moved the first element. So when you are at the next element with "even" index, the element that's there was originally at an odd index. Thus, after you shift the first element, you can just directly continue with the element at the next index, which previously was two indices away, then again the next one, and so on, for half the indices in the list.

Here's an example, using a list of numbers so it's easier to see what happens. If you want odd indices instead, use range(1, len(lst)//2+1).

lst = list(range(10))
for i in range(len(lst)//2):
    lst.append(lst.pop(i))
# [1, 3, 5, 7, 9, 0, 2, 4, 6, 8]

However, even if this works, modifying a list while iterating it is generally a very bad idea leading to many headaches. Also, that repeated pop(i) makes the whole operation O(n²).

Instead, it would be much faster and saner to just combine two slices of the list:

lst = list(range(10))
lst = lst[1::2] + lst[0::2]
# [1, 3, 5, 7, 9, 0, 2, 4, 6, 8]

(If you need to change the list "in-place", e.g. because of other references pointing to that list, you can replace the content of the list using an assignment to a slice: lst[:] = .... This would still not be "in-place" in the sense of not using additional memory. But if the list is so big that this is a problem, then the O(n²) running time will probably be a bigger problem anyway.)

tobias_k
  • 81,265
  • 12
  • 120
  • 179
0

A simple way would be to build a new list by using comprehensions:

lst2 = [v for i, v in enumerate(lst) if i%2 == 0] + \
       [v for i, v in enumerate(lst) if i%2 != 0]

But it is possible to change the list in place. The rule is to start from the end of the list in order not to change oddness of indices when an element is removed

last = len(lst) - 1   # when an element is popped, the list loses one element
for i in range(len(lst), 0, -1):
    if (i % 2) == 0:
        val = lst.pop(i - 1)       # remove element with even index
        lst.insert(last, val)      # insert it before last inserted
        last -= 1
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • thats cooooooool bro , really Thank u so much thats really help , I really appreciate it , thank you really ✌❤️ – RECUR May 17 '22 at 07:18
  • 1
    @BilelBibou: Please do not forget to accept an answer if you no longer need help with that question – Serge Ballesta May 17 '22 at 07:30
  • yes of cource but how i do it , is some how i cant – RECUR May 17 '22 at 07:35
  • @LancelotduLac it did , i wanted the indices not the value and this the only one answer (2nd part) that solve my approach , i dont care about the value , i care about the indexes of the values, got it ? – RECUR May 17 '22 at 07:51