1

I try to remove all characters in the database that are smaller than a chosen character i. The database is a list of lists of characters.

def project(database, i):
    test = database.copy()
    for idx,lists in enumerate(database.copy()):
        for char in lists:
            print(char)
            if char <= i:
                test[idx].remove(char)
     return test

a = [['A','B','D'],['A','B','C','D']]
print(project(a, 'C'))


Output:
A D A C
[['B', 'D'], ['B', 'D']]

Somehow the code never checks for 'B' although it is in the list. The same code without the if condition + remove line (line 5-6) does the following:

Output:
A B D A B C D
['A', 'B', 'D'], ['A', 'B', 'C', 'D']]

Why does the printed character change although I do not change the iterated list?

Robin S.
  • 11
  • 1
  • `test` is _not_ a copy of the `database`. Well, it is - but it is a shallow copy. It contains references to the original inner lists. You need a deep copy. – DYZ Aug 29 '17 at 00:09
  • I was afraid that changing the matrix that I am iterating through maybe explains the weird behaviour. I just checked the code without all copies, it does the same. – Robin S. Aug 29 '17 at 00:13
  • Please read the answers, at least one of them explains how to make a deep copy. – DYZ Aug 29 '17 at 00:16
  • Deep copy fixed this how? – Erich Aug 29 '17 at 00:25
  • Possible duplicate of [Why is my for loop skipping an element in my list?](https://stackoverflow.com/questions/33344413/why-is-my-for-loop-skipping-an-element-in-my-list) – Erich Aug 29 '17 at 00:41

3 Answers3

1

After debugging:

The issue is not because of your if statement, It is because remove change the index.

Let mt demonstrate that:

  • after first iterate with removing A the list will be:

    ["B", "D"]
    

And your index will be 1, because of that "B" will be ignored.

Fady Saad
  • 1,169
  • 8
  • 13
0

Your issue has to do with your copying of the list database.

Per the python.org docs:

A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.

A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.

If you deep copy copy.deepcopy(x) your list, then you will get a separate object that is not a reference of the other, but rather, a full copy.

Community
  • 1
  • 1
Davy M
  • 1,697
  • 4
  • 20
  • 27
  • Also see [This question](https://stackoverflow.com/questions/243836/how-to-copy-all-properties-of-an-object-to-another-object-in-python) – Davy M Aug 29 '17 at 00:12
0

As it has been already mentioned in the other answers, your code has two issues: one with shallow copying and the other with modifying the list that is being iterated. However, you do not even need all this complexity. In your case, it is cheaper to retain the "good" items than to remove the "bad" items:

def project(database, i):
    return [[item for item in lst if item >= i] for lst in database]

print(project(a, 'C'))
# [['D'], ['C', 'D']]

By the way, the condition char <= i removes the items that are smaller than or equal to i, not just smaller than i.

DYZ
  • 55,249
  • 10
  • 64
  • 93