How do I pop() from a list without using pop()?

4.8k views Asked by At

I have a function called pop_item() that I am trying to make act like a pop() that works with the list class, how would I do that, here is my code: def empty(lst): return lst == []

def pop_item(lst):
    lst = lst[::-1]
    new_lst = []
    for i in lst:
        if i != lst[-1]:
            new_lst += [i]
    lst = new_lst
    return lst

def main():
    todo = [1,2,3,4]

    print(todo) #prints [1,2,3,4] as expected


    print('\n' + 75 * '_' + '\n')

    print(pop_item(todo)) #pop the item off
    print(todo) #output should then be [1,2,3]

if __name__ == '__main__':
    main()

Note: I am not allowed to use any built in functions eg len(),index,del() etc.

3

There are 3 answers

2
teja kommuru On
li= [1,2,3,4]
def popl(li)
 li=li[1:]
popl(li)
print(li)
2
ShadowRanger On

Dramatically more efficient than listcomps and broad slicing is using a single-item slice assignment:

def pop_item(lst, index=-1):  # index is -1 by default so it pops from the end
    obj = lst[index]          # Save off the object being popped to return it
    lst[index:index+1 or None] = ()  # Remove it from the list
    return obj                # Return the saved off object to the caller

lst[index:index+1 or None] = () is equivalent to del lst[index], aside from never throwing exceptions; thankfully, the indexing operation on the prior line will throw the exception for us.

The del version is essentially how list.pop is implemented, and it's amortized O(1) work (when index is the default -1) and a single O(n) operation when it's popping from elsewhere in the list (as opposed to slicing and listcomps, which involve multiple O(n) shallow copy operations, no matter where you pop from).

Your original code differed from list.pop in that:

  1. It deleted based on value, not index
  2. It could delete multiple items, not just one
  3. It reversed the input for no apparent reason
  4. It left the input unchanged rather than removing an item from the caller's list
  5. It returned a mutated copy of the input list, rather than the popped item

The replacement has none of these issues, and behaves essentially identically to list.pop.

5
Jean-François Fabre On

Here are a few variants of popping items from a list without using list functions, only slicing & list comprehension

pop the last item using slicing & slicing assignment:

def pop_item(lst):
    lst[:] = lst[:-1]

pop a valued item (last one but can be a parameter) by rebuilding the list & slice assign

def pop_item(lst):
    lst[:] = [x for x in lst if x!=lst[-1]]

(that can pop other items in the list if they have the same value)

by speciftying item position/index in the list:

def pop_item(lst,item_position):
    lst[:] = [x for i,x in enumerate(lst) if i!=item_position]