All test cases passed except one which is throwing key error - python-3.x

We are given a directed graph, with nodes labeled 0, 1, ..., n-1 and each edge is either red or blue, and there could be self-edges or parallel edges.
Each [i, j] in red_edges denotes a red directed edge from node i to node j. Similarly, for blue_edges.
Return an array 'answer' of length n, where each answer[X] is the length of the shortest path from node 0 to node X such that the edge colors alternate along the path (or -1 if such a path doesn't exist).
I'm not getting where's the problem in the code.
n = 3, red_edges = [[0,1],[1,2]], blue_edges = []
n = 3, red_edges = [[0,1]], blue_edges = [[2,1]]
n = 3, red_edges = [[0,1]], blue_edges = [[1,2]]
n = 3, red_edges = [[1,0]], blue_edges = [[2,1]]
d={}
result=[-1]*(n)
for i in red_edges:
if i[0] not in d:
d[i[0]]=[i[1]]
else:
d[i[0]].append(i[1])
if i[0]==0:
result[i[1]]=1
#print(d)
for j in blue_edges:
if j[0] not in d:
d[j[0]]=[j[1]]
else:
d[j[0]].append(j[1])
if j[0]==0:
result[j[1]]=1
elif j[0]!=0:
if j[0] in d[0]: #This is Line 24 which is throwing error.
result[j[1]]=2
else:
pass
if 0 in d[0]:
result[0]=1
else:
result[0]=0
#print(d)
print(result)
Key in 'd' is equal to the starting node and value in a key-value pair has a list in which all the endpoints corresponding to that key are inserted.
Moreover, in each for loop, I'm also preparing my result array if any edge is present between node zero and node equal to the index of the result array. e.g, I'll insert 1 in result array for index 1 if it has a direct link with node zero else I'll keep it as -1. And if any index has indirect link( as in test case 2: blue_edges =[[2,1]]) then I'll check in d[0] if first element of blue_edges is present. If it is present then I'll insert 2 else -1.
expected=actual=[0,1,-1]
expected=actual=[0,1,-1]
expected=actual=[0,1,1]
expected=[0,-1,-1] but in 4th case it is throwing an error.
Line 24: KeyError: 0

I switched to using defaultdict(list) so that if d is empty for some value, you'll just get an empty list.
In your case - it eliminates the error and logically matches the if.
it also help clean up many if/elses.
try this:
from collections import defaultdict
cases = [
(3, [[0, 1], [1, 2]], []),
(3, [[0, 1]], [[2, 1]]),
(3, [[0, 1]], [[1, 2]]),
(3, [[1, 0]], [[2, 1]]),
]
for n, red_edges, blue_edges in cases:
d = defaultdict(list)
result = [-1] * n
result[0] = 0
for src, dst in red_edges:
d[src].append(dst)
if src == 0:
result[dst] = 1
for src, dst in blue_edges:
d[src].append(dst)
if src == 0:
result[dst] = 1
else:
if src in d[0]:
result[dst] = 2
print(result)
Output:
[0, 1, -1]
[0, 1, -1]
[0, 1, 2]
[0, -1, -1]

Related

Get the distance from every element in a list to any other element

I have a list:
l = [10,22,3]
I'm trying to create a function that returns the distances (how close they are in the list itself), such that elements on the left of any element has a negative value, and those on its right has a positive value:
#optimal output
dis = [[0,1,2],[-1,0,1],[-2,-1,0]]
Is there a quick way to do that?
You could try a nested for-in loop. The idea here is to just retrieve the indexes of each value and its distance from other values.
nums = [10, 22, 3]
distances = []
for i in range(len(nums)):
for n in range(len(nums)):
distances.append(i-n)
print(distances)
Output:
[0, -1, -2, 1, 0, -1, 2, 1, 0]
Also, never name a variable l, because it looks like a 1.
Based on Leonardo's answer, to do what the OP commented:
nums = [10, 22, 3]
distances = []
for i in range(len(nums)):
temp = []
for n in range(len(nums)):
temp.append(n-i)
distances.append(temp)
print(distances)
Output:
[[0, 1, 2], [-1, 0, 1], [-2, -1, 0]]

matrix addition giving wrong answer

I am from java background, I am learning python matrix operation. I have an assignment question to add two matrices manually I can't figure out the error in my logic. need help thank you
x = [[12,7,3],[4 ,5,6],[7 ,8,9]]
y = [[5,8,1],[6,7,3],[4,5,9]]
row = len(x)
col = len(x[0])
ans = [[0] * col] * row
for i in range(len(x)):
for j in range(len(x[i])):
ans[i][j] = x[i][j] + y[i][j]
print()
print(ans)
output :
[[11, 13, 18], [11, 13, 18], [11, 13, 18]]
The problem is here:
ans = [[0]*col]*row
This statement creates row number of objects, where each object is [[0]*col]. What this means is that, each "sub-list" in the list is pointing to the same list.
(More information about this behaviour here: List of lists changes reflected across sublists unexpectedly)
You can verify that by checking the id values of ans[0],ans[1] and so on:
>>> a = [[0]*col]*row
>>>
>>> a
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> id(a[0])
140336190913992
>>> id(a[1])
140336190913992
>>> id(a[2])
140336190913992
This means, if we set a[0][1] = 10 (say), then EACH sub-list will have the the value 10 set. This is because all the lists point to the same list.
i.e.
>>> a[0][1] = 10
>>> a
[[0, 10, 0], [0, 10, 0], [0, 10, 0]]
Now, how do we avoid this?
You can do so by initiliasing the ans list in a different way, as in:
b = [[0 for x in range(col)] for y in range(row)]
You can verify that all the sub-lists point to different addresses by using id again:
>>> id(b[0])
140336190512520
>>> id(b[1])
140336190765000
>>> id(b[2])
140336197031816
So now if you run your original program, you will get desired results.
TLDR; your modified program looks like this:
x = [[12,7,3],[4 ,5,6],[7 ,8,9]]
y = [[5,8,1],[6,7,3],[4,5,9]]
row = len(x)
col = len(x[0])
ans = [[0 for x in range(col)] for y in range(row)]
for i in range(len(x)):
for j in range(len(x[i])):
ans[i][j] = x[i][j] + y[i][j]
print(ans)

Counting instances of N in an array using Recursion in Python

I would like to count the number of instances of a given number N in an array using recursion. For example, given:
array = [1, 2, 3, 1, 1, 4, 5, 2, 1, 8, 1]
and N = 1, the function should return 5.
This problem can be solved using the .counter attribute as shown here. However, I am looking to not use any in-built functions or attributes.
Here's my attempt to solve this using recursion but I get a count of 1 and not 5. What am I doing wrong?
def count_val(array, n, count=0):
if len(array) == 0:
return None
# Base Case
if len(array) == 1:
if array[0] == n:
count += 1
else:
count_val(array[1:], n, count)
if array[0] == n:
count += 1
return count
print(count_val2(array, 1))
1
I think for an empty array, the value should be 0 (len == 0 should be the base case), and, you don't need to have a count parameter if you just return the count, your function could be reduced to this:
def count_val(array, n):
if len(array) == 0:
return 0
return (array[0] == n) + count_val(array[1:], n)
array = [1, 2, 3, 1, 1, 4, 5, 2, 1, 8, 1]
print(count_val(array, 1))
Output:
5
You can have it as a one-liner as well (as suggested by #blhsing):
def count_val(array, n):
return len(array) and (array[0] == n) + count_val(array[1:], n)
What am I doing wrong?
The function you wrote will always keep only the last few characters, so after a while it will be [1, 8, 1], after that [8, 1] and after that [1], which returns 1. The array never contains just any of the other 1s.
An easy way to do this is to loop over all elements in a list and test if they are equal to N.
array = [1, 2, 3, 1, 1, 4, 5, 2, 1, 8, 1]
def count_val(array, n):
if len(array) == 0:
return 0
count=0
for i in array:
if i==n:
count += 1
return count
print(count_val(array, 1))
This returns 5.

Compute distance metric in a complete graph

Suppose I have an array, namely Map. Map[i][j] means the distance between area i and area j. Under this definition, we get:
a) Map[i][i] always equals 0.
b) Map[i][k] <= Map[i][j] + Map[j][k] for all i,j,k
I want to build a function func(Map,k) returning a metric D, while D[i][j] is the shortest distance of a route from area i to area j, and this route should pass through at least k different area.
This is my python code to do so:
def func(Map,k):
n=len(Map)
D_temp = [list(x) for x in Map]
D = [list(x) for x in Map]
for m in range(k - 1):
for i in range(n):
for j in range(n):
tmp = [D[i][x] + Map[x][j] for x in range(n) if x != i and x != j]
D_temp[i][j] = min(tmp)
D = [list(x) for x in D_temp]
return D
func([[0, 2, 3], [2, 0, 1], [3, 1, 0]],2)
return a distance metric D which equals [[4, 4, 3], [4, 2, 5], [3, 5, 2]]
D[0][0] equals 4, because the shortest route from area0 to area0 which pass through at least 2 area is {area0-->area1-->area0}, and the distance of the route is Map[0][1]+Map[1][0]=2+2=4
Wanted to know what would be the best way to do that?
You can use the A* algorithm for this, using Map[i][j] as the heuristic for the minimum remaining distance to the target node (assuming that, as you said, Map[i][j] <= Map[i][x] + Map[x][j] for all i,j,x). The only difference to a regular A* would be that you only accept paths if they have a minimum length of k.
import heapq
def min_path(Map, k, i, j):
heap = [(0, 0, i, [])]
while heap:
_, cost, cur, path = heapq.heappop(heap)
if cur == j and len(path) >= k:
return cost
for other in range(len(Map)):
if other != cur:
c = cost + Map[cur][other]
heapq.heappush(heap, (c + Map[other][j], c, other, path + [other]))
Change your func to return a list comprehension using this min_path accordingly.
def func(Map, k):
n = len(Map)
return [[min_path(Map, k, i, j) for i in range(n)] for j in range(n)]
res = func([[0, 2, 3], [2, 0, 1], [3, 1, 0]], 2)
This gives me the result [[4, 4, 3], [4, 2, 3], [3, 3, 2]] for len(path) >= k, or [[4, 4, 3], [4, 2, 5], [3, 5, 2]] for len(path) == k.

how to fix python fibonacci sequence script?

My assignment is to create a function that produces 3 lists of the numbers in the fibonacci sequence starting at 0. Here is my code so far.
def fibList(n):
a = 0; b = 1; fibList = []
if n <= 0:
return
elif n == 1:
fibList = [a]
elif n == 2:
fibList = [a,b]
else:
for i in range(0,n):
a, b = b, a + b
fibList.append(b)
return fibList
def main():
print (fibList(4))
print (fibList(10))
print (fibList(-4))
what i want my output to look like is [0,1,1,2] for 4, [0,1,1,2,3,5,8,13,21,34,55] for 10, and [] for -4
My issue begins with fibList(4) currently giving an output of [1, 2, 3, 5] and fibList(10) gives an output of [1, 2, 3, 5, 8, 13, 21, 34, 55, 89] and for -4 I get "None" instead of a [].
If I type in fibList(1) I get [0] and for fibList(2) I get [0, 1], but when i test fibList(3) the first 0 and 1 are lost, giving me [1,2,3]
How would I go about making it so any number above 3 starts with [0, 1, 1, 2...]? My main issue is getting the 0 and 1 to be the first two numbers in the sequence and getting fibList(-4) to produce a [].
any help or tips would be greatly appreciated :-)
All that you are missing is to add an empty list in the case of less than or equal to zero, and recurse correctly over your range of Fibonacci numbers greater than 2. Making those small changes like so:
def fibList(n):
if n <= 0:
fibnums = []
elif n == 1:
fibnums = [0]
elif n >= 2:
fibnums = [0, 1]
for i in range(2,n):
fibnums.append(fibnums[i-1]+fibnums[i-2])
return fibnums
Note that this recursive method can get quite slow for large numbers, if that is of concern to you with your program. Best of luck!
With these changes,
print (fibList(4)) => [0, 1, 1, 2]
print (fibList(10)) => [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
print (fibList(-4)) => []
You did not quite define your function. Should the resulting list have n values [f(0), ..., f(n-1)] or n+1 values [f(0), ..., f(n)]? Your examples are contradictory: the 'expected' output for 4 has 4 values ending with f(3) while that for 10 has 11 values ending with f(10).
I am going to assume that the latter is correct. Here is a revised version of your fast iterative solution. (If my assumption is wrong, stop the range at n instead of n+1.)
def fibs(n):
"Return [fib(0), ..., fib(n)."
ret = [0, 1] # fib(0), fib(1)
a, b = ret
if n <= 1:
return ret[:n+1]
else:
for i in range(2, n+1):
a, b = b, a+b # b = f(i)
ret.append(b)
return ret
print(fibs(-4), fibs(0), fibs(2), fibs(4), fibs(10))
#
[] [0] [0, 1, 1] [0, 1, 1, 2, 3] [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

Resources