python list of lists index out of range [closed] - python

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I have read in a matrix of numbers and I am trying to work with each cell and perform tests on each one. If the number is != 0 I want to use it so if it is 0 I am currently incrementing x and y to find a non zero number.
In the end I will just be first looking across the top row and then if they are all 0 start looking down the first column and this works fine as long as I am referring to just one (row or column).
Why am I receiving this error? Am I thinking incorrectly about how the cells are set up or is my code wrong?
The matrix looks like this:
0,2,4,1,6,0,0
2,0,0,0,5,0,0
4,0,0,0,0,5,0
1,0,0,0,1,1,0
6,5,0,1,0,5,5
0,0,5,1,5,0,0
0,0,0,0,5,0,0
When I start trying to do this:
y = y + 5
x = x + 5
node = Alist[x][y]
I receieve an error saying:
node = Alist[x][y]
IndexError: list index out of range
If I was to just write:
y = y + 5
node = Alist[x][y]
print node
It would work completely fine but when I introduce both x and y I start to get list index out of range problems. In my mind it should now read:
node = Alist[5][5]
Which is 0 if you follow the matrix
def create_matrix(file):
with open('network.txt') as f:
Alist = []
for line in f:
part = []
for x in line.split(','):
part.append(int(x))
Alist.append(part)
return Alist
#used to set the start node, used once
def start_node(Alist):
x=0
y=0
#point node to pos [0][0] of Alist
node = Alist[x][y]
#test if node == 0
while node == 0:
y = y + 5
x = x + 5
node = Alist[x][y]
#create a list to hold co-ordinates
if node != 0:
#return node for processing by check_neighbours
return node, x, y
#def current_node(Alist, x, y)
#test neighbours to see if they can be used
def check_neighbours(node, Alist, i, j):
#print out values of x and y
print "x = %d" %i
print "y = %d" % j
print "node in check_neighbours is " + str(node)
#running of code begins here
def main():
file = ("F:/media/KINGSTON/Networking/network.txt")
Alist = create_matrix(file)
node, x, y = start_node(Alist)
check_neighbours(node, Alist, x, y)
main()

It's the second iteration round the loop that's failing, because it sets x and y to 10, where you only have 7 items in each dimension.
Your loop while node == 0: moves down the diagonal of the matrix five steps at a time, falling off the end. It would fall off the end even if it went one at a time, because that diagonal is all zeros.
Perhaps you meant if node == 0?
I don't know what the code is actually trying to do, but you need to rethink the algorithm. :-)

If I follow your code in start_node you are
a) Not performing any kind of bounds checking
and
b) Jumping down the diagonal elements of your matrix, which are all zero, until you go out of bounds, as your error tells you. Presumably when you are incrementing only one of your indices you are lucky in that you hit a non-zero element before going out of bounds

In this code, start_node returns the first non-zero "node".
I used mat instead of Alist as I feel it is more Pythonic.
Comments note the changes and tips.
def create_matrix(fname): # don't use built-ins as variable names!!
with open(fname) as f: # you take filename in arguments, but don't use it..
# why not use in-built functions and list comprehensions ?
mat = [map(int,line.split(',')) for line in f]
return mat
#used to set the start node, used once
def start_node(mat):
# for each row in matrix (index)..
for i1 in range(len(mat)):
# for each cell in row (index)..
for i2 in range(len(mat[i1])):
# mat[i1][i2] is the node/cell..
if mat[i1][i2] != 0:
# return node, x, y :)
return mat[i1][i2], i2, i1
# test neighbours to see if they can be used
# same as yours
def check_neighbours(node, Alist, i, j):
#print out values of x and y
print "x = %d" % (i,)
print "y = %d" % (j,)
print "node (in check_neighbours) is " + str(node)
#running of code begins here
def main():
fname = "F:/media/KINGSTON/Networking/network.txt"
mat = create_matrix(fname)
node, x, y = start_node(mat)
check_neighbours(node, mat, x, y)
main()
Explanation:
mat = [map(int,line.split(',')) for line in f]
This is a list comprehension. map is an in-built method.
The for loops in start_node...
for i1 in range(len(mat)): # 1
for i2 in range(len(mat[i1])): # 2
len(mat) is the number of rows in your matrix.
range(len(mat)) gives us the indexes of each row.
len(mat[i1]) gives us the length of the current row.
range(len(mat[i1])) gives us the indexes of each column in that row.
In your code, you were incrementing both x and y (here i2 and i1 respectively) so were moving diagonally.

Related

Finding maximum values (of one raster) which are inside each segment of another raster

There are two rasters as below. One consisting of only four values [1,2,3,4]. The other, consisting of values between 800 to 2500. The problem is to go through all of the raster-1 regions and find the maximum values of raster-2 which are located inside each region or segment.
In theory, it seems simple but I can't find a way to implement it. I'm reading scikit image documentation and I'm getting more confused. In theory, it would be:
for i in raster1rows:
for j in i:
# where j is a part of closed patch, iterate through the identical
# elements of raster-2 and find the maximum value.
There is another problem inherent to this question which I can't post as a different topic. As you can see, there are a lot of isolated pixels on raster-1, which could be interpreted as a region and produce a lot of additional maximums. to prevent this I used :
raster1 = raster1.astype(int)
raster1 = skimage.morphology.remove_small_objects(raster1 , min_size=20, connectivity=2, in_place=True)
But raster-1 seems to take no effect.
To remove the small object I've done
array_aspect = sp.median_filter(array_aspect, size=10)
And it gave me good results.
To find maximum elevation inside each closed part I've done:
# %%% to flood-fill closed boundaries on the classified raster
p = 5
ind = 1
for i in rangerow:
for j in rangecol:
if array_aspect[i][j] in [0, 1, 2, 3, 4]:
print("{}. row: {} col: {} is {} is floodfilled with {}, {} meters".format(ind, i, j, array_aspect[i][j], p, array_dem[i][j]))
array_aspect = sk.flood_fill(array_aspect, (i,j), p, in_place=True, connectivity=2)
p = p + 1
else:
pass
ind = ind + 1
# %%% Finds the max elev inside each fill and returns an array-based [Y,X, (ELEV #in meters)]
p = 5
maxdems = {}
for i in rangerow:
for j in rangecol:
try:
if bool(maxdems[array_aspect[i][j]]) == False or maxdems[array_aspect[i][j]][-1] < array_dem[i][j]:
maxdems[array_aspect[i][j]] = [i, j, array_dem[i][j]]
else:
pass
except: #This is very diabolical, but yeah :))
maxdems[array_aspect[i][j]] = [i, j, array_dem[i][j]]
print(maxdems)`
I've got my desired results.

Python List in List trouble

Before start to tell my problem sorry for my grammar and English is not very good. I'm a Python learner. Today i was working on a project but I have a trouble. I'm trying to make a loop.
coordinates = [[1,2],[2,3],[3,5],[5,6],[7,7`],[1,2]]
Here is my list, I'm trying to create a loop. That loop will substract every first values from each others and every seconds to seconds then print. Let me explain my trouble more simple. [[x,y][x1,y1][x2,y2] I need to substract x1-x then print the result after this x2-x1 then print the result but same time y1-y print then print so console output should looks like this;
1,1
1,2
2,1...
Method i've tried
while True:
for x,y in coordinates:
x = x - y
print(x)
This is not worked because it substracts x values to y values. I know it's too wrong.
I've research on internet but i did not understand this subject very well.
I'm looking for help. Thanks everyone.
A simple and naive implementation
def pr(arr):
i = 1
while i < len(arr):
(x,y) = arr[i]
(a,b) = arr[i-1]
print(x-a, y-b)
i += 1
if __name__ == '__main__':
coordinates = [[1,2],[2,3],[3,5],[5,6],[7,7],[1,2]]
pr(coordinates)
O/P:
1 1
1 2
2 1
2 1
-6 -5
This is fairly similar to your original code:
coordinates = [[1,2],[2,3],[3,5],[5,6],[7,7`],[1,2]]
x_prev = None
for x, y in coordinates:
if x_prev is not None:
print('{}, {}'.format(x - x_prev, y - y_prev)
x_prev, y_prev = x, y
If you want to generalize a bit, for different lengths of coordinates, you could do this:
coordinates = [[1,2],[2,3],[3,5],[5,6],[7,7`],[1,2]]
prev = None
for c in coordinates:
if prev is not None:
print(', '.join(c2-c1 for c1, c2 in zip(prev, c)))
prev = c
You need to iterate over the list using range function so that you can get current and next ones together. So you can do the subtraction in the loop.
coordinates = [[1,2],[2,3],[3,5],[5,6],[7,7],[1,2]]
for i in range(len(coordinates) - 1):
print(coordinates[i+1][0] - coordinates[i][0], coordinates[i+1][1] - coordinates[i][1])

how to sum adjacent tuples/list

I apologise for the terrible description and if this is a duplicated, i have no idea how to phrase this question. Let me explain what i am trying to do. I have a list consisting of 0s and 1s that is 3600 elements long (1 hour time series data). i used itertools.groupby() to get a list of consecutive keys. I need (0,1) to be counted as (1,1), and be summed with the flanking tuples.
so
[(1,8),(0,9),(1,5),(0,1),(1,3),(0,3)]
becomes
[(1,8),(0,9),(1,5),(1,1),(1,3),(0,3)]
which should become
[(1,8),(0,9),(1,9),(0,3)]
right now, what i have is
def counter(file):
list1 = list(dict[file]) #make a list of the data currently working on
graph = dict.fromkeys(list(range(0,3601))) #make a graphing dict, x = key, y = value
for i in list(range(0,3601)):
graph[i] = 0 # set all the values/ y from none to 0
for i in list1:
graph[i] +=1 #populate the values in graphing dict
x,y = zip(*graph.items()) # unpack graphing dict into list, x = 0 to 3600 and y = time where it bite
z = [(x[0], len(list(x[1]))) for x in itertools.groupby(y)] #make a new list z where consecutive y is in format (value, count)
z[:] = [list(i) for i in z]
for i in z[:]:
if i == [0,1]:
i[0]=1
return(z)
dict is a dictionary where the keys are filenames and the values are a list of numbers to be used in the function counter(). and this gives me something like this but much longer
[[1,8],[0,9],[1,5], [1,1], [1,3],[0,3]]
edits:
solved it with the help of a friend,
while (0,1) in z:
idx=z.index((0,1))
if idx == len(z)-1:
break
z[idx] = (1,1+z[idx-1][1] + z[idx+1][1])
del z[idx+1]
del z[idx-1]
Not sure what exactly is that you need. But this is my best attempt of understanding it.
def do_stuff(original_input):
new_original = []
new_original.append(original_input[0])
for el in original_input[1:]:
if el == (0, 1):
el = (1, 1)
if el[0] != new_original[-1][0]:
new_original.append(el)
else:
(a, b) = new_original[-1]
new_original[-1] = (a, b + el[1])
return new_original
# check
print (do_stuff([(1,8),(0,9),(1,5),(0,1),(1,3),(0,3)]))

backtracking not trying all possibilities

so I've got a list of questions as a dictionary, e.g
{"Question1": 3, "Question2": 5 ... }
That means the "Question1" has 3 points, the second one has 5, etc.
I'm trying to create all subset of question that have between a certain number of questions and points.
I've tried something like
questions = {"Q1":1, "Q2":2, "Q3": 1, "Q4" : 3, "Q5" : 1, "Q6" : 2}
u = 3 #
v = 5 # between u and v questions
x = 5 #
y = 10 #between x and y points
solution = []
n = 0
def main(n_):
global n
n = n_
global solution
solution = []
finalSolution = []
for x in questions.keys():
solution.append("_")
finalSolution.extend(Backtracking(0))
return finalSolution
def Backtracking(k):
finalSolution = []
for c in questions.keys():
solution[k] = c
print ("candidate: ", solution)
if not reject(k):
print ("not rejected: ", solution)
if accept(k):
finalSolution.append(list(solution))
else:
finalSolution.extend(Backtracking(k+1))
return finalSolution
def reject(k):
if solution[k] in solution: #if the question already exists
return True
if k > v: #too many questions
return True
points = 0
for x in solution:
if x in questions.keys():
points = points + questions[x]
if points > y: #too many points
return True
return False
def accept(k):
points = 0
for x in solution:
if x in questions.keys():
points = points + questions[x]
if points in range (x, y+1) and k in range (u, v+1):
return True
return False
print(main(len(questions.keys())))
but it's not trying all possibilities, only putting all the questions on the first index..
I have no idea what I'm doing wrong.
There are three problems with your code.
The first issue is that the first check in your reject function is always True. You can fix that in a variety of ways (you commented that you're now using solution.count(solution[k]) != 1).
The second issue is that your accept function uses the variable name x for what it intends to be two different things (a question from solution in the for loop and the global x that is the minimum number of points). That doesn't work, and you'll get a TypeError when trying to pass it to range. A simple fix is to rename the loop variable (I suggest q since it's a key into questions). Checking if a value is in a range is also a bit awkward. It's usually much nicer to use chained comparisons: if x <= points <= y and u <= k <= v
The third issue is that you're not backtracking at all. The backtracking step needs to reset the global solution list to the same state it had before Backtracking was called. You can do this at the end of the function, just before you return, using solution[k] = "_" (you commented that you've added this line, but I think you put it in the wrong place).
Anyway, here's a fixed version of your functions:
def Backtracking(k):
finalSolution = []
for c in questions.keys():
solution[k] = c
print ("candidate: ", solution)
if not reject(k):
print ("not rejected: ", solution)
if accept(k):
finalSolution.append(list(solution))
else:
finalSolution.extend(Backtracking(k+1))
solution[k] = "_" # backtracking step here!
return finalSolution
def reject(k):
if solution.count(solution[k]) != 1: # fix this condition
return True
if k > v:
return True
points = 0
for q in solution:
if q in questions:
points = points + questions[q]
if points > y: #too many points
return True
return False
def accept(k):
points = 0
for q in solution: # change this loop variable (also done above, for symmetry)
if q in questions:
points = points + questions[q]
if x <= points <= y and u <= k <= v: # chained comparisons are much nicer than range
return True
return False
There are still things that could probably be improved in there. I think having solution be a fixed-size global list with dummy values is especially unpythonic (a dynamically growing list that you pass as an argument would be much more natural). I'd also suggest using sum to add up the points rather than using an explicit loop of your own.

Python - speed up pathfinding

This is my pathfinding function:
def get_distance(x1,y1,x2,y2):
neighbors = [(-1,0),(1,0),(0,-1),(0,1)]
old_nodes = [(square_pos[x1,y1],0)]
new_nodes = []
for i in range(50):
for node in old_nodes:
if node[0].x == x2 and node[0].y == y2:
return node[1]
for neighbor in neighbors:
try:
square = square_pos[node[0].x+neighbor[0],node[0].y+neighbor[1]]
if square.lightcycle == None:
new_nodes.append((square,node[1]))
except KeyError:
pass
old_nodes = []
old_nodes = list(new_nodes)
new_nodes = []
nodes = []
return 50
The problem is that the AI takes to long to respond( response time <= 100ms)
This is just a python way of doing https://en.wikipedia.org/wiki/Pathfinding#Sample_algorithm
You should replace your algorithm with A*-search with the Manhattan distance as a heuristic.
One reasonably fast solution is to implement the Dijkstra algorithm (that I have already implemented in that question):
Build the original map. It's a masked array where the walker cannot walk on masked element:
%pylab inline
map_size = (20,20)
MAP = np.ma.masked_array(np.zeros(map_size), np.random.choice([0,1], size=map_size))
matshow(MAP)
Below is the Dijkstra algorithm:
def dijkstra(V):
mask = V.mask
visit_mask = mask.copy() # mask visited cells
m = numpy.ones_like(V) * numpy.inf
connectivity = [(i,j) for i in [-1, 0, 1] for j in [-1, 0, 1] if (not (i == j == 0))]
cc = unravel_index(V.argmin(), m.shape) # current_cell
m[cc] = 0
P = {} # dictionary of predecessors
#while (~visit_mask).sum() > 0:
for _ in range(V.size):
#print cc
neighbors = [tuple(e) for e in asarray(cc) - connectivity
if e[0] > 0 and e[1] > 0 and e[0] < V.shape[0] and e[1] < V.shape[1]]
neighbors = [ e for e in neighbors if not visit_mask[e] ]
tentative_distance = [(V[e]-V[cc])**2 for e in neighbors]
for i,e in enumerate(neighbors):
d = tentative_distance[i] + m[cc]
if d < m[e]:
m[e] = d
P[e] = cc
visit_mask[cc] = True
m_mask = ma.masked_array(m, visit_mask)
cc = unravel_index(m_mask.argmin(), m.shape)
return m, P
def shortestPath(start, end, P):
Path = []
step = end
while 1:
Path.append(step)
if step == start: break
if P.has_key(step):
step = P[step]
else:
break
Path.reverse()
return asarray(Path)
And the result:
start = (2,8)
stop = (17,19)
D, P = dijkstra(MAP)
path = shortestPath(start, stop, P)
imshow(MAP, interpolation='nearest')
plot(path[:,1], path[:,0], 'ro-', linewidth=2.5)
Below some timing statistics:
%timeit dijkstra(MAP)
#10 loops, best of 3: 32.6 ms per loop
The biggest issue with your code is that you don't do anything to avoid the same coordinates being visited multiple times. This means that the number of nodes you visit is guaranteed to grow exponentially, since it can keep going back and forth over the first few nodes many times.
The best way to avoid duplication is to maintain a set of the coordinates we've added to the queue (though if your node values are hashable, you might be able to add them directly to the set instead of coordinate tuples). Since we're doing a breadth-first search, we'll always reach a given coordinate by (one of) the shortest path(s), so we never need to worry about finding a better route later on.
Try something like this:
def get_distance(x1,y1,x2,y2):
neighbors = [(-1,0),(1,0),(0,-1),(0,1)]
nodes = [(square_pos[x1,y1],0)]
seen = set([(x1, y1)])
for node, path_length in nodes:
if path_length == 50:
break
if node.x == x2 and node.y == y2:
return path_length
for nx, ny in neighbors:
try:
square = square_pos[node.x + nx, node.y + ny]
if square.lightcycle == None and (square.x, square.y) not in seen:
nodes.append((square, path_length + 1))
seen.add((square.x, square.y))
except KeyError:
pass
return 50
I've also simplified the loop a bit. Rather than switching out the list after each depth, you can just use one loop and add to its end as you're iterating over the earlier values. I still abort if a path hasn't been found with fewer than 50 steps (using the distance stored in the 2-tuple, rather than the number of passes of the outer loop). A further improvement might be to use a collections.dequeue for the queue, since you could efficiently pop from one end while appending to the other end. It probably won't make a huge difference, but might avoid a little bit of memory usage.
I also avoided most of the indexing by one and zero in favor of unpacking into separate variable names in the for loops. I think this is much easier to read, and it avoids confusion since the two different kinds of 2-tuples had had different meanings (one is a node, distance tuple, the other is x, y).

Categories

Resources