What ways can we use to remove elements from a list in Python?

Phillip, you have very nicely summarized all three situations

  1. alias: new_lst = my_lst
  2. “shallow” copy (top layer only): new_lst = copy(my_lst) (& other methods, as above.)
  3. “deep” copy (separate copy all the way down): new_lst = copy.deepcopy(my_lst)

If you Google “Python list copying” you get about 8.5 million hits; here is one that summarizes things nicely

1 Like

Addendum with respect to copying objects

When we want to be sure that our copy is indeed a copy, and not a reference to the original. check its id.

>>> p = [1, 2, 3]
>>> id(p)
140669632471176
>>> q = p
> id(q)
140669632471176
>>> 

If the ids match, it’s not a copy, but a reference, only.

>>> id(199)
140669688098336
>>> x = 199
>>> id(x)
140669688098336
>>> 

Above we can see how Python will give a number value an id. There is only ever one value in memory of any one number, never more. When we assign that number to a variable, it still has the same id.

That will be the case no matter what structure we use the number in.

>>> u = [1, 9, 19, 99, 199]
>>> id(u[4])
140669688098336
>>> v = {'one': 1, 'one-ninety-nine': 199}
>>> id(v['one-ninety-nine'])
140669688098336
>>>

As for copies, that is true copies, or clones,

>>> id(u)
140669625218312
>>> w = u.copy()
>>> id(w)
140669625233288
>>> id(w[4])
140669688098336
>>> 

Note the last id. Granted the two lists are unique, now, but any values they have in common ARE the same value in memory.

This parallels through all objects, regardless their data type. There is only ever one of any one value in memory.

1 Like

Thank you, for taking the time to respond. This is very helpful. The link also cleared a couple of things up for me.

@mtf: Thank you very much as well. I think the id() check will be very useful going forward.

2 Likes

Hi guys.
What do you think about my way to solve this task? It’s quite different than the original solution what we get by pressing the solution button.

delete%20starting%20even%20numbers

When working with lists we always need to consider whether we wish to intentionally mutate or possibly destroy the original list, as has been discussed. Can we do this without affecting the original?

Yes, we can…

>>> def delete_starting_evens(lst):
	for i, x in enumerate(lst):
		if x % 2:
			return lst[i:]
	return []

>>> lst = [2,4,6,7,6,5,4,3]
>>> delete_starting_evens(lst)
[7, 6, 5, 4, 3]
>>> delete_starting_evens([])
[]
>>> delete_starting_evens([2,4,6,8,10])
[]
>>> lst
[2, 4, 6, 7, 6, 5, 4, 3]
>>> 

Direct inputs don’t matter since they only exist in the argument, not somewhere in memory. A list that exists in memory is mutable by the function we pass it into. How we manipulate the list inside the function has a direct effect on the list in memory.

Bottom line, if it is not our clear intention to mutate an existing data structure, then special care must be taken to either not alter the list, or to create a spin-off list of only the data we want and return that; or, like above, don’t alter the list in any way and only return the portion (slice) of the list that suits our purpose.

I don’t quite grasp how the provided solution function works (see solution), specifically with lst = lst[1:]

If a list parameter were to consist of only 1 number–as becomes any list consisting of only even numbers as it is processed by the loop function–which would have an index of 0, how does using the slicing language lst[1:] function properly in this case?

2 Likes

i think the “for i in lst” statement makes the program iterate through every component and len(lst)>0
condition makes sure before the loop starts to run both of the conditions are met; so if lst has only one component , it will satisfy the condition of len(lst)>0 beside the modulo operator condiditon and while loop will run.

1 Like

i didn’t get how the duplication part works

The following addresses that and related issues.

Let’s consider the difference between identity and equivalence in Python.

In Python, objects are identical if they are, in fact, the same object.

Objects are considered to be equivalent if they have the same value. There are some minor exceptions that recognize equivalence of values that are similar, but not of the same type. See the end of this post for an example.

If objects are identical, they are also equivalent. However, if they are equivalent, they are not necessarily also identical. The following may help clarify the difference between identity and equivalence regarding Python lists.

To help with the discussion, we will be using the following operators:

  • is: tests for identity
  • ==: tests for equivalence

Let’s create two lists with the same content. They will be equivalent, but not identical.

>>> a = [1, 2, 3, 4, 5, 6, 7]
>>> b = [1, 2, 3, 4, 5, 6, 7]
>>> a == b # are they equivalent?
True
>>> a is b # are they identical?
False

With lists, the = operator assigns a reference to the list specified by the expression on the right side of the operator to a variable on the left side of the operator. Let’s demonstrate that by creating a list, assigning it to c, then assigning c to d. This will create only one list, Both c and d will refer to that same list. Therefore, c and d will be identical and also equivalent.

>>> c = [1, 2, 3, 4, 5, 6, 7]
>>> d = c
>>> c == d
True
>>> c is d
True

Taking a slice of a list creates a new list. We can use this as a means of making a copy of a list. Let’s try that with two variables, e, and f.

>>> e = [1, 2, 3, 4, 5, 6, 7]
>>> f = e[:] # this slice includes all of the elements in e
>>> e == f
True
>>> e is f
False

Recall that a and b are equivalent, but not identical. Let’s modify a and find out whether that affects b.

>>> a.append(8) # 8 gets appended to a, but not to b
>>> a
[1, 2, 3, 4, 5, 6, 7, 8]
>>> b
[1, 2, 3, 4, 5, 6, 7]

b was not affected.

Recall that c and d are identical. Let’s modify c and find out whether that affects d.

>>> c.append(8) # 8 gets appended to c, which affects d
>>> c
[1, 2, 3, 4, 5, 6, 7, 8]
>>> d
[1, 2, 3, 4, 5, 6, 7, 8]

Modifying c modified d, because both variables refer to the same list.

When a list is passed to a function as an argument, the corresponding function parameter will refer to the same list as the argument. If we wish to work with a copy of the list instead of with the original, we must make a copy of the list. Within the above examples, we used a slice to assign a copy of e to f. Alternatively, we could have used the list function to create the copy, as follows:

>>> f = list(e)
>>> e == f
True
>>> e is f
False

As promised above, here is an equivalence between lists that contain items that differ in type:

>>> [1.0, 0.0, 1.0] == [True, False, True]
True

Edited on September 6, 2019 to modify the final example

1 Like

Please correct me if i am wrong.

Your mention of first instance (or may me i did not understand what you meant) as quoted above sound a bit confusing. I tried it (see below code) by removing the element in index 1 , and it worked.


In [13]: list = [1, 2, 3, 1]                                                    

In [14]: list.remove(2)                                                         

In [15]: print(list)                                                            
[1, 3, 1]


My understanding of your first instance is that the remove() function take out the first element or element in index 0 in the list.

Kindly help me learn more

Consider,

>>> lst = [1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> lst.remove(1)
>>> lst
[2, 3, 1, 2, 3, 1, 2, 3]
>>> 

The fact that 1 is found at the first index has no bearing, only that it is the first instance of that value.

>>> lst.remove(1)
>>> lst
[2, 3, 2, 3, 1, 2, 3]
>>> 

By implication, first instance here means the first 1 that appears in the element, right?

as in the first element to contain a 1. We are searching for values, regardless of index. So, yes, instance refers to value.

1 Like

Thank you very much mtf

1 Like

This was a super helpful reminder as I’m trying to understand where I was going wrong using .remove().
Thank-you!

1 Like

After reading through the thread and giving myself the time to focus on the answer, I get it. I was stuck at: lst = lst[1:] - understanding why it was done this way versus using .remove() or .pop() on the first item of the list ( item at index [0]).
Thank-you to those who asked questions and those who provide such thorough answers!

1 Like

def delete_starting_evens(lst):
while len(lst) > 0 and lst[0] % 2 == 0:
lst.pop(0)
return lst

Can someone explain to me why the code above with the return function is correct while the code on the bottom is incorrect?

def delete_starting_evens(lst):
while len(lst) > 0 and lst[0] % 2 == 0:
lst.pop(0)
print(lst)

Hello, @bit2637307750.

From the instructions:
image

return hands a value back to the caller, and terminates the function.
print() simply prints a value, so we can see it. It does not return anything. A function that doesn’t include an explicit return statement will implicitly return None in Python. When the SCT for the exercise checks your code, None is being returned instead of lst.

P.S. For future posts, please review How do I format code in my posts?

I also got confused, not sure what’s wrong with the code I wrote:
The result showed function if not defined. Need some help here!

def delete_starting_events(lst):
  for num in lst:
    if lst[0] % 2 == 0: 
      lst = lst [:1]
    else: 
      return lst

Spelling error, perhaps?