Reputation: 5388
What I want the code to do is to print the list containing numbers that are:
There should be no 5-digit numbers and some 6-digit numbers in the final list as they are less than 101101. But there still are some 5-digit numbers after processing. Why is that happening?
list1 = []
for i in range(100, 1000):
for j in range(100, 1000):
if str(i*j) == str(i*j)[::-1]: # checking for palindrome
list1.append(i*j)
list1 = list(set(list1)) # removing duplicates
print(sorted(list1))
# print(len(list1))
for ii in list1: # removing numbers, out of range
if ii < 101101 or ii >= 1000000:
list1.remove(ii)
print(sorted(list1))
# print(len(list1))
But when I use sets to remove the elements out of range, it works. The below given code does the job.
set1 = set(range(10000, 101102))
list1 = list(set(list1) - set1)
But I am not understanding, why the previous code fails to print the desired output?
Edit: As 1 of you suggested, yes it is a duplicate of this. My bad for not checking for the question in the existing bank.
Upvotes: 0
Views: 119
Reputation: 114230
This is a textbook example of why you don't modify a list in-place. The culprit is this loop:
for ii in list1: # removing numbers, out of range
if ii < 101101 or ii >= 1000000:
list1.remove(ii)
The initial parts of list1
are all going to be 5 digits long, as you already noticed. List iterators step along by index. Let's take a look at what happens when you remove an element from a list of 5-digit numbers:
Start with a list, and ii
referencing the first number:
10001, 20002, 30003, 40004, ...
^
ii
Remove ii
from the list:
20002, 30003, 40004, ...
ii -> 10001
ii
is still a valid reference, but not to an item in the list. The list has naturally shifted back by one element.
Continue the loop to the next element:
20002, 30003, 40004, ...
^
ii
Hopefully you can see how that skips adjacent elements that you want to filter out.
You have a number of viable workarounds. Here are a few to get you started:
Use a list comprehension to make a new list:
list1 = [x for x in list1 if len(x) > 5]
Get rid of the offending loop entirely, and only append a string to the list on the first loop if it's longer than the retirement.
Iterate backwards, so the shifts don't affect you:
for ii in reversed(list1):
if ii < 101101 or ii >= 1000000:
list1.remove(ii)
OR
for ii in range(len(list1), -1, -1):
if list1[ii] < 101101 or list1[ii] >= 1000000:
del list1[ii]
Personally, I'd recommend option 2 since it's the least hassle in the end. You don't even need to check the length of the string, just whether the number is greater than 99999.
Upvotes: 1
Reputation: 24028
This is the most simple way to solve your problem;
list1 = []
for i in range(100, 1000):
for j in range(100, 1000):
if str(i*j) == str(i*j)[::-1]: # checking for palindrome
list1.append(i*j)
# Use list comprehension to filter unwanted values from the list.
list1 = sorted([value for value in set(list1) if 101101 <= value < 1000000])
print(list1)
Upvotes: 1