From a performance point of view:
mylist = mylist[2:-2]anddel mylist[:2];del mylist[-2:]are equivalent- they are around 3 times faster than the first solution
for _ in range(2): mylist.pop(0); mylist.pop()
Code
iterations = 1000000
print timeit.timeit('''mylist=range(9)\nfor _ in range(2): mylist.pop(0); mylist.pop()''', number=iterations)/iterations
print timeit.timeit('''mylist=range(9)\nmylist = mylist[2:-2]''', number=iterations)/iterations
print timeit.timeit('''mylist=range(9)\ndel mylist[:2];del mylist[-2:]''', number=iterations)/iterations
output
1.07710313797e-06
3.44465017319e-07
3.49956989288e-07
Answer from mxdbld on Stack OverflowFrom a performance point of view:
mylist = mylist[2:-2]anddel mylist[:2];del mylist[-2:]are equivalent- they are around 3 times faster than the first solution
for _ in range(2): mylist.pop(0); mylist.pop()
Code
iterations = 1000000
print timeit.timeit('''mylist=range(9)\nfor _ in range(2): mylist.pop(0); mylist.pop()''', number=iterations)/iterations
print timeit.timeit('''mylist=range(9)\nmylist = mylist[2:-2]''', number=iterations)/iterations
print timeit.timeit('''mylist=range(9)\ndel mylist[:2];del mylist[-2:]''', number=iterations)/iterations
output
1.07710313797e-06
3.44465017319e-07
3.49956989288e-07
You could slice out a new list, keeping the old list as is:
mylist=['a','b','c','d','e','f','g','h','i']
newlist = mylist[2:-2]
newlist now returns:
['c', 'd', 'e', 'f', 'g']
You can overwrite the reference to the old list too:
mylist = mylist[2:-2]
Both of the above approaches will use more memory than the below.
What you're attempting to do yourself is memory friendly, with the downside that it mutates your old list, but popleft is not available for lists in Python, it's a method of the collections.deque object.
This works well in Python 3:
for x in range(2):
mylist.pop(0)
mylist.pop()
In Python 2, use xrange and pop only:
for _ in xrange(2):
mylist.pop(0)
mylist.pop()
Fastest way to delete as Martijn suggests, (this only deletes the list's reference to the items, not necessarily the items themselves):
del mylist[:2]
del mylist[-2:]
How do I pop multiple items from a queue? (python)
Why pop method removes two list at once?
python - How to remove multiple indexes from a list at the same time? - Stack Overflow
How do I add multiple things to a pop list in Python?
Videos
Specifically, I am wondering how to take all numbers less than 50 from a queue. I am not having trouble with adding numbers or moving them, but with removing them after they're moved. I am getting the following error: "IndexError: pop index out of range". I'm using VisualStudio Code if that matters.
I'm doing the Python Crash Course and I got to this exercise, and I was wondering why the pop method is removing two list of my guest.
guest = ['aaron', 'john', 'pedro', 'kevin', 'mark', 'brad']
print(guest)
guest.pop()
print(f"{guest.pop()}")
print(guest)
Output:
['aaron', 'john', 'pedro', 'kevin', 'mark', 'brad']
mark
['aaron', 'john', 'pedro', 'kevin']I tried assigning it with variable now it works. How is it different from the first though?
guest = ['aaron', 'john', 'pedro', 'kevin', 'mark', 'brad']
print(guest)
guest_1 = guest.pop()
print(f"{guest_1}")
print(guest)
Output:
['aaron', 'john', 'pedro', 'kevin', 'mark', 'brad']
brad
['aaron', 'john', 'pedro', 'kevin', 'mark']
You need to do this in a loop, there is no built-in operation to remove a number of indexes at once.
Your example is actually a contiguous sequence of indexes, so you can do this:
del my_list[2:6]
which removes the slice starting at 2 and ending just before 6.
It isn't clear from your question whether in general you need to remove an arbitrary collection of indexes, or if it will always be a contiguous sequence.
If you have an arbitrary collection of indexes, then:
indexes = [2, 3, 5]
for index in sorted(indexes, reverse=True):
del my_list[index]
Note that you need to delete them in reverse order so that you don't throw off the subsequent indexes.
remove_indices = [1,2,3]
somelist = [i for j, i in enumerate(somelist) if j not in remove_indices]
Example:
In [9]: remove_indices = [1,2,3]
In [10]: somelist = range(10)
In [11]: somelist = [i for j, i in enumerate(somelist) if j not in remove_indices]
In [12]: somelist
Out[12]: [0, 4, 5, 6, 7, 8, 9]
I'm working on a project where I have to invite a bunch of people to a party yadda yadda yadda. Long story short I have to pop a bunch of names from my list. I want to add them to a new list because they are no longer invited (I know, I'm an asshole). Then use that list to send out a cancellation notice. I'm able to pop one name successfully and add it to "popped_names" but I don't quite know how to add more people to "popped_friends." Or does pop just not work that way? Here is a snippet of the code I'm working with. Mainly the "problem" part, everything else I think is kind of useless:
popped_friends = friends.pop(0)
friends.append('Kara')
friends.insert(3 , 'Anna')
friends.insert(0, 'Candace')
for name in friends:
print("Hi", name.title(), 'would you like to come over for dinner? I found a bigger table!')
print('\nHey sorry guys. The bigger table wont be here on time so I can only invite 2 people. Sorry!')
popped_friends = friends.pop(0)
popped_friends = friends.pop(2)
popped_friends = friends.pop(2)
print(popped_friends)
for name in popped_friends:
print("Sorry" , name.title(), "I don't have room at the table anymore")The problem in particular is towards the end after I tell everyone I can only invite a few people. The reason I'm asking is because that loop at the end outputs this:
Sorry A I don't have room at the table anymore Sorry N I don't have room at the table anymore Sorry N I don't have room at the table anymore Sorry A I don't have room at the table anymore
Which leads me to believe that "Anna" is the only person in the list because.
Does pop even work this way? Or am I crazy?
Are your lists large? If so, use ifilter from itertools to filter out elements that you don't want lazily (with no up front cost).
Lists not so large? Just use a list comprehension:
newlist = [x for x in oldlist if x not in ['a', 'c'] ]
This will create a new copy of the list. This is not generally an issue for efficiency unless you really care about memory consumption.
As a happy medium of syntax convenience and laziness ( = efficiency for large lists), you can construct a generator rather than a list by using ( ) instead of [ ]:
interestingelts = (x for x in oldlist if x not in ['a', 'c'])
After this, you can iterate over interestingelts, but you can't index into it:
for y in interestingelts: # ok
print y
print interestingelts[0] # not ok: generator allows sequential access only
You want a list comprehension:
L = [c for c in L if c not in ['a', 'c']]
Or, if you really don't want to create a copy, go backwards:
for i in reversed(range(len(L))):
if L[i] in ['a', 'c']:
L.pop(i) # del L[i] is more efficient
Thanks to ncoghlan for reversed() & phooji for del L[i] suggestions. (I decided to leave it as L.pop(i), since that's how the question was initially formulated.)
Also, as J.S. Sebastian correctly points out, going backwards is space efficient but time inefficient; most of the time a list comprehension or generator (L = (...) instead of L = [...]) is best.
Edit:
Ok, so since people seem to want something less ridiculously slow than the reversed method above (I can't imagine why... :) here's an order-preserving, in-place filter that should differ in speed from a list comprehension only by a constant. (This is akin to what I'd do if I wanted to filter a string in c.)
write_i = 0
for read_i in range(len(L)):
L[write_i] = L[read_i]
if L[read_i] not in ['a', 'c']:
write_i += 1
del L[write_i:]
print L
# output: ['b', 'd']