python: when for accesses the sequence, it modifies the sequence again and again. What's the problem

Keywords: Python PAT

An instance

Take a basic topic: PAT (Basic Level) Practice 1005: continue 3n+1 to show this problem.
For a detailed description of the topic, see the PAT website.

Problem solving ideas

1. After writing the input data, convert the sequence to be verified into the list num of digital elements_ list.

2. Traverse num from scratch_ List, for each element num, study the 3n+1 conjecture, and update num, if the updated num is in num_list, from num_ remove it from the list.

3.num_ There are only "key numbers" left in the list, which are sorted by the built-in function sorted (reverse=True).

4. for traverses sorted_num_list[:-1], print(num, end = "). Then print(sorted_num_list[-1], end =").

Problem solving code

length = int(input())
s = input()
num_list = [int(n) for n in s.split(" ")]
for num in num_list:
    while num != 1:
        if num % 2 == 0:
            num = num // 2
        else:
            num = (3 * num + 1) // 2
        if num in num_list:
            num_list.remove(num)
sorted_num_list = sorted(num_list, reverse=True)
for n in sorted_num_list[:-1]:
    print(n, end=" ")
print(sorted_num_list[-1], end="")

Code test

Input:

6
3 5 6 7 8 11

Output:

11 7 6

However, the correct output is: "7 6".

What's the problem?

Normally, 11 is overwritten by 7 and will be deleted when traversing 7. However, it is not.

Through the debug research, it is found that it is related to the traversal mechanism of for - for traverses seq from small to large (i=0,1,2,..., len(seq)-1) through the index i of seq:

If the element traversed by the first (i=0) is 3, then 5 and 8 are deleted from SEQ and seq becomes "3,6,7,11".

The next (i=1) traverses 6, then 3 is deleted from SEQ and seq becomes "6, 7, 11".

Then the next (i=2) traversal is 11, then no element is deleted and seq remains unchanged.

When len(seq)-1 is already 2, it will not be traversed, so seq will not traverse 7, so 11 is reserved. This code is incorrect.

On the other hand, there are even relevant suggestions on this issue in the official documents:

In particular!! we should notice that for traverses copy() in the figure!!

The traversed copy does not change due to the change of the original sequence, but always looks like the original - it means that the. copy() function only executes the first time when the program is executed! And then the returned variable is always used!

However, if you traverse seq instead of seq.copy(), the debug test finds that the sequence of for traversal is changed.

In other words, for traversal sequence, every time an element is accessed, the traversed sequence must be read. If the returned value of a function is traversed, the function will only execute the first time.

How to solve the problems caused by for and give the code solution of the above example?

The official document has given a hint: create another sequence to assist.

In addition, in this problem, we should do: if the number has been covered, we should not study its "3n+1".

We can use another sequence covered_list to store the covered numbers,
When each number to be verified is accessed, first judge whether it is in covered_list and decide whether to study its "3n+1".
In the process of studying the "3n+1" of a number, add the found covered number to the covered_list.
Last sort [n for n in num_list if n not in covered_list].

code:

length = int(input())
s = input()
num_list = [int(n) for n in s.split(" ")]
# A new list: covered_list to save the number that has been "covered". If num not in covered_list, study the conjecture.
covered_list = []
for num in num_list:
    if num not in covered_list:
        while num != 1:
            if num % 2 == 0:
                num = num // 2
            else:
                num = (3 * num + 1) // 2
            if num in num_list:
                covered_list.append(num)
sorted_num_list = sorted([num for num in num_list if num not in covered_list], reverse=True)
for n in sorted_num_list[:-1]:
    print(n, end=" ")
print(sorted_num_list[-1], end="")

Unexpected problem: is there another mystery between. copy() and for loop?

I don't understand what's going on –
The following code can get full marks, but it does not successfully avoid all the numbers "covered". It seems that only the number of the first element "covered" avoids the study of "3n+1".

length = int(input())
s = input()
num_list = [int(n) for n in s.split(" ")]
for num in num_list:
    print(num_list)
    print(num)
    while num != 1:
        if num % 2 == 0:
            num = num // 2
        else:
            num = (3 * num + 1) // 2
        if num in num_list:
            num_list.remove(num)
    num_list = num_list.copy()
sorted_num_list = sorted(num_list, reverse=True)
for n in sorted_num_list[:-1]:
    print(n, end=" ")
print(sorted_num_list[-1], end="")

Output (11 was "covered" by 7 and should have been remove d first, but it was still accessed and studied "3n+1"):

[3, 5, 6, 7, 8, 11]
3
[3, 6, 7, 11]
6
[6, 7, 11]
7
[6, 7]
11
7 6

. copy() is executed every time, and then for only takes the original num_list, and the first. Copy(): [3, 6, 7, 11].

For is the first copy() except that the original num_list is accessed for the first access sequence.

Posted by joelhop on Fri, 01 Oct 2021 15:34:29 -0700