1

I'm codding a kind of program to encrypt some text using matrices, and I need to replace some numbers in to letters. This is my code so far:

letters = {"1": "A"}
X = [[1, 1, 1],[1, 1, 1]]
for list_in in X:
    for number in list_in:
        new_value = letters[str(number)]
        list_in[number] = new_value
for row in X:
    print(row)

But, I'm getting the following error:

KeyError: 'A'

I have no idea of what is wrong. Sorry if it is a bad question, but I didn't found any question similar to this one.

Vitor
  • 762
  • 6
  • 26
  • So you want to replace all the elements in the list (or list of lists) based on your `letters`, resulting something like`[['A', 'A', 'A'], ['A', 'A', 'A']]`? – Chris May 14 '19 at 02:18
  • @Chris Exactly!! – Vitor May 14 '19 at 02:19
  • Possible duplicate of [Python: Replacing item in a list of lists](https://stackoverflow.com/questions/2104796/python-replacing-item-in-a-list-of-lists) – Chris May 14 '19 at 02:20

2 Answers2

2

The problem in your earlier code is the age-old one Iterating on the list while modifying it, which has caused the exception.

You are modifying list_in in the inner loop while iterating over it when you do list_in[number] = new_value, and this causes new_value to become A in the next loop, which is not a valid key in letters, hence you get the error KeyError: 'A'

I would suggest using list comprehension to achieve what you want, which creates a new list while iterating on the old one, which is what we would like to happen

letters = {"1": "A"}
X = [[1, 1, 1],[1, 1, 1]]

res = [[letters[str(item)] for item in li] for li in X ]
print(res)
#[['A', 'A', 'A'], ['A', 'A', 'A']]

Note that the inner for loop can also be written in another way using map

letters = {"1": "A"}
X = [[1, 1, 1],[1, 1, 1]]

res = [list(map(lambda x:letters[str(x)], li)) for li in X ]
print(res)

Note that this is equivalent to the following traditional double for loops, which might be easier to understand

letters = {"1": "A"}
X = [[1, 1, 1],[1, 1, 1]]

res = []
#Iterate over outer list
for li in X:
    l = []
    #Iterate over inner list and append A for inner list
    for item in li:
        l.append(letters[str(item)])
    #Append this list to a bigger list
    res.append(l)

print(res)

As an addendum, the original code can be made to work by using indexes to change the value instead of replacing items, using enumerate

letters = {"1": "A"}
X = [[1, 1, 1],[1, 1, 1]]

#Iterate over the lists
for i, li in enumerate(X):
    for j, item in enumerate(li):
        #Replace value at index i,j with A
        X[i][j] = letters[str(item)]

print(X)
Devesh Kumar Singh
  • 20,259
  • 5
  • 21
  • 40
1

You can use list comprehension with list(map(...)):

print([list(map(lambda x: letters[str(x)], i)) for i in X])

That which outputs:

[['A', 'A', 'A'], ['A', 'A', 'A']]
U13-Forward
  • 69,221
  • 14
  • 89
  • 114