Asked  7 Months ago    Answers:  5   Viewed   64 times

I'm telling my program to print out line 53 of an output. Is this error telling me that there aren't that many lines and therefore can not print it out?

 Answers

41

If you have a list with 53 items, the last one is thelist[52] because indexing starts at 0.

IndexError

  • Attribution to Real Python: Understanding the Python Traceback - IndexError

The IndexError is raised when attempting to retrieve an index from a sequence (e.g. list, tuple), and the index isn’t found in the sequence. The Python documentation defines when this exception is raised:

Raised when a sequence subscript is out of range. (Source)

Here’s an example that raises the IndexError:

test = list(range(53))
test[53]

---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-6-7879607f7f36> in <module>
      1 test = list(range(53))
----> 2 test[53]

IndexError: list index out of range

The error message line for an IndexError doesn’t provide great information. See that there is a sequence reference that is out of range and what the type of the sequence is, a list in this case. That information, combined with the rest of the traceback, is usually enough to help quickly identify how to fix the issue.

Tuesday, June 1, 2021
 
Evernoob
answered 7 Months ago
57

When you write [x]*3 you get, essentially, the list [x, x, x]. That is, a list with 3 references to the same x. When you then modify this single x it is visible via all three references to it:

x = [1] * 4
l = [x] * 3
print(f"id(x): {id(x)}")
# id(x): 140560897920048
print(
    f"id(l[0]): {id(l[0])}n"
    f"id(l[1]): {id(l[1])}n"
    f"id(l[2]): {id(l[2])}"
)
# id(l[0]): 140560897920048
# id(l[1]): 140560897920048
# id(l[2]): 140560897920048

x[0] = 42
print(f"x: {x}")
# x: [42, 1, 1, 1]
print(f"l: {l}")
# l: [[42, 1, 1, 1], [42, 1, 1, 1], [42, 1, 1, 1]]

To fix it, you need to make sure that you create a new list at each position. One way to do it is

[[1]*4 for _ in range(3)]

which will reevaluate [1]*4 each time instead of evaluating it once and making 3 references to 1 list.


You might wonder why * can't make independent objects the way the list comprehension does. That's because the multiplication operator * operates on objects, without seeing expressions. When you use * to multiply [[1] * 4] by 3, * only sees the 1-element list [[1] * 4] evaluates to, not the [[1] * 4 expression text. * has no idea how to make copies of that element, no idea how to reevaluate [[1] * 4], and no idea you even want copies, and in general, there might not even be a way to copy the element.

The only option * has is to make new references to the existing sublist instead of trying to make new sublists. Anything else would be inconsistent or require major redesigning of fundamental language design decisions.

In contrast, a list comprehension reevaluates the element expression on every iteration. [[1] * 4 for n in range(3)] reevaluates [1] * 4 every time for the same reason [x**2 for x in range(3)] reevaluates x**2 every time. Every evaluation of [1] * 4 generates a new list, so the list comprehension does what you wanted.

Incidentally, [1] * 4 also doesn't copy the elements of [1], but that doesn't matter, since integers are immutable. You can't do something like 1.value = 2 and turn a 1 into a 2.

Tuesday, June 1, 2021
 
dkcwd
answered 7 Months ago
59

Just use a containment test:

if redList in totalList:

This returns True for your sample data:

>>> totalList = [ [[0,1], [2,7], [6,3]], [[2,3], [6,1], [4,1]] ]
>>> redList = [ [0,1], [2,7], [6,3] ]
>>> redList in totalList
True
Thursday, August 5, 2021
 
TMichel
answered 4 Months ago
21

You probably have a blank row in your csv file, causing it to produce an empty list

There are a couple solutions


1. Check if there are elements, only proceed if there are:

for row in exchReader:
    if len(row):  # can also just do   if row:
        currency = row[0]
        if currency == crntCurrency:

2. Short-circuit an and operator to make currency an empty list, which won't match crntCurrency:

for row in exchReader:
    currency = row and row[0]
    if currency == crntCurrency:
Saturday, August 14, 2021
 
Jesse
answered 4 Months ago
25

First read the text file and get the line contents into a numpy array, with this :

with open('test1.txt', 'r') as f:
    all_lines = f.readlines()
    mat_shape = tuple(map(int, all_lines[0].split()))
    lines = [i.strip().split() for i in all_lines[1:]]
lines = np.array(lines)

Read the first line of the text file, split, map them into int and keep it in a tuple as we use it to resize our matrix later.

lines would be like this :

[['*' 'o' 'o' 'o' 'o' '*']
 ['o' 'o' '*' 'o' 'o' 'o']
 ['o' 'o' '*' 'o' 'o' '*']
 ['o' 'o' '*' 'o' 'o' 'o']
 ['o' 'o' 'o' 'o' '*' 'o']
 ['o' 'o' 'o' 'o' 'o' 'o']]

Get the neighbor items for each cell of the matrix, with this function :

def get_neighbours(lines, cell):
    row, col = cell
    row_max = len(lines)
    col_max = len(lines[0])
    cell_cont = lines[row][col]
    if cell_cont!="*":
        return [lines[row_d + row][col_d + col] for col_d in [-1,0,1] if (0 <= (col_d + col) < col_max) or (col_d == 0 and row_d==0) for row_d in [-1,0,1] if 0 <= (row_d + row) < row_max ].count('*')
    else:
        return '*'

The function takes whole matrix and a particular cell which is a tuple of row and column number. It returns only '*' if there is a star in the cell, otherwise an integer - the number of stars in the adjacent neighbor cells.

Now create a new array, and call this function for each cell of the matrix :

new = []
for i,_ in enumerate(lines):
    for j,_ in enumerate(lines[i]):
        new.append(get_neighbours(lines, (i,j)))
new = np.array(new)

If you now reshape this matrix into the desired format by this :

new = new.reshape(mat_shape)

It becomes :

[['*' '2' '1' '1' '1' '*']
 ['1' '3' '*' '2' '2' '2']
 ['0' '3' '*' '3' '1' '*']
 ['0' '2' '*' '3' '2' '2']
 ['0' '1' '1' '2' '*' '1']
 ['0' '0' '0' '1' '1' '1']]

You can write this into a new text file with this :

with open('new1.txt', 'w') as f:
    f.write(all_lines[0])
    for i in new:
        f.write(' '.join(i))
        f.write('n')

It would write the following content into the new1.txt file :

6 6
* 2 1 1 1 *
1 3 * 2 2 2
0 3 * 3 1 *
0 2 * 2 2 2
0 1 1 2 * 1
0 0 0 1 1 1
Wednesday, October 27, 2021
 
Sidarta
answered 1 Month ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share