Lists in Python

Hello everybody,

i am a beginner in Python and i am learning Data Structures now.
Could anybody help me to understand why two codes below produce different results?

You may copy these two codes in this online Python compiler and visual debugger, click ‘Visualize Exercution’ and take notice how the value of i and how the content of the list roll_number change in each iteration of the for loop, then you may find there’s something unusual in the running of the second code.

2 Likes

It can also be useful to put some print statements within your loop to see what’s happening to your i variable and list at each iteration of the loop.

Second example looks like you’re trying to repair a car while someone is driving it.

1 Like

When you edit a list while iterating through, you will get strange results. The index will change. You should make a copy and update accordingly.

1 Like

Hello,
I have two rules for you as the beginner, try to remember forever.

  1. “Never use list() when you are making a copy of an existing list”, just assign it
list=[47,64,69,37,76,83,105,97]
new_list=list

here is one rule for you as the beginner - “Never change an element of the list in case of for loop”. It’s causing Index Error. Instead of, you should to put in another list.

print("CASE 1")
roll_number=[47,64,69,37,76,83,105,97]
sample_dict={'Jhon':47,'Emma':69,'Kelly':76,'Jason':97}
sample_dicts=list(sample_dict.values())
roll_number_new=[]
for rnum in roll_number:
    if rnum in sample_dicts:
       roll_number_new.append(rnum)
print(f"Final outcome: {roll_number_new}")

Here is an example with for in range() loop, if you try to remove it inside of the loop, it raise IndexError, I handle with try-except.

print("CASE 2")
roll_number1=[47,64,69,37,76,83,105,97]
for ind in range(len(roll_number1)):
    try:
        if roll_number1[ind] not in sample_dicts:
           roll_number1.remove(roll_number1[ind])
    except IndexError:
       print("You already removed that element")
print(f"Final outcome: {roll_number1}")

I hope it would be helpful for you.

2 Likes

Hi Aleks! Thank you very much for your detailed explanation, i appreciate it. Thanks :slight_smile:

You should not use the python built list to name a list. Doing a copy is fine.

Take this example

alist = [1,2,3,4,5]

#copying blist
blist = alist

#using copy
clist = alist.copy()

#pop element
blist.pop()

# alist changes because they are both pointing to the same thing
print(f'alist -> {alist}')

print(f'blist -> {clist}')

#clist doesn't change because it's a different pointer
print(f'clist -> {clist}')

See Python&Math

I haven’t seen anyone explain what’s going on and what the difference is so I’ll go ahead and do that. What’s happening in the first set of code, where you are modifying the original list, is that as you remove items, the for-in loop is skipping past indices its already scanned, for efficiency’s sakes. You could easily create something using this methodology, and have it return the output you expect, but that’d be a confirmation bias, meaning that although your output was correct, the method of getting that output was actually not.

When you did it the 2nd way, by copying the list, the indices in the original list remained intact, allowing the for loop to execute in the way you expect. That is a more resource intensive way if you have large lists, but it does still work.

There are a lot more memory efficient ways to do something like this, in as little as one line of code, but something tells me you haven’t gotten into using lambdas or filters quite yet.

Edit:

I meant to add the one liner solution for this:

roll_number = [47, 64, 69, 37, 76, 83, 105, 97]

sample_dict = { 'Jhon':47, 'Emma':69, 'Kelly':76, 'Jason':97 }

# A single line, memory efficient method of reducing the list to only values present in the sample_dict values
roll_number_new = list(filter(lambda i: i in sample_dict.values(), roll_number))

print(roll_number_new)

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.