Is there a way to reduce this? - python

I have this code where st is an array of a class that have x and y parameters. I have to sort their x or y. How can i reduce it so i dont have to write the same code 2 times (one for each case)?
def sort(st, coor):
for i in range(len(st)):
if coor == 'x':
selected = st[i]
j = i - 1
while j >= 0 and st[j].x > selected.x:
st[j + 1], st[j] = st[j], st[j + 1]
j -= 1
st[j + 1] = selected
i += 1
else:
selected = st[i]
j = i - 1
while j >= 0 and st[j].y > selected.y:
st[j + 1], st[j] = st[j], st[j + 1]
j -= 1
st[j + 1] = selected
i += 1

Extract a method for the code that is duplicated.
https://refactoring.guru/extract-method
In that new method, the part that is different is calling the x or y attribute of an instance, and this can be replaced by a call to getattr.

Related

Generate Randomized Color Board

generate a random (height x width) grid such that for every coordinate (i, j), there can be no three consecutive same colors in a row or in a column.
generate(int: width, int: height, list: colors)
Example:
getvalidMatrix(3, 3, [0, 1, 2])
output:
[
[1, 2, 1],
[1, 0, 2],
[0, 1, 2],
]
import random
def getvalidMatrix(length,width,colors):
map = dict()
for i in range(len(colors)):
map[colors[i]]=i
res = [[0] * length] * width
for i in range(length):
for j in range(width):
end = len(colors)
if i - 1 >= 0 and i - 2 >= 0 and res[i-1][j] == res[i-2][j]:
index = map[res[i-1][j]]
colors[index] = colors[end]
colors[end] = map[res[i-1]][j]
end -= 1
if j - 1 >= 0 and j - 2 >= 0 and res[i][j-1] == res[i][j-2]:
index = map[res[i][j-1]]
colors[index] = colors[end]
colors[end] = map[res[i][j-1]]
end -= 1
next=random.randint(0,end)
res[i][j] = colors[next]
return res
if __name__ == '__main__':
length = 3
width = 3
colors = [0,1,2]
print(getvalidMatrix(length, width, colors))
I got IndexError: list index out of range with the code above. Which part of the code should I fix in order to avoid the IndexError?
Although I didn't completely understand de algorithm used to solve the problem, I can see that you are committing a few mistakes:
You're retrieving a multidimensional list element incorrectly, e.g., list_var[a][b] instead of list_var[b][a]. This can be solved in the for loops.
You're indexing variable colors this way: colors[end] = ..., but variable end is initialized as end = len(colors), i.e., with a value 1 unit greater than the maximum index allowed, remember that lists are zero-indexed.
A misplaced closing bracket.
Here's the corrected code. Run a file diff to see the changes I've made. I don't guarantee it now solves the problem you were given but the errors you came across are gone.
import random
def getvalidMatrix(length,width,colors):
map = dict()
for i in range(len(colors)):
map[colors[i]]=i
res = [[0] * length] * width
for i in range(width):
for j in range(length):
end = len(colors)-1
if i - 1 >= 0 and i - 2 >= 0 and res[i-1][j] == res[i-2][j]:
index = map[res[i-1][j]]
colors[index] = colors[end]
colors[end] = map[res[i-1][j]]
end -= 1
if j - 1 >= 0 and j - 2 >= 0 and res[i][j-1] == res[i][j-2]:
index = map[res[i][j-1]]
colors[index] = colors[end]
colors[end] = map[res[i][j-1]]
end -= 1
next=random.randint(0,end)
res[i][j] = colors[next]
return res
if __name__ == '__main__':
length = 3
width = 3
colors = [0,1,2]
print(getvalidMatrix(length, width, colors))

Finding runs of integers

I have a problem that asks me to write a program that has a defined list (as the argument) and will then find all runs of Y consecutive numbers that increase or decrease by 1. It will then return the list of indices of the first element of each of these runs.
For example, if Y = 3, then l1 = [1,2,3,5,10,9,8,9,10,11,7,8,7] returns [0,4,6,7]. I got the code working somewhat, but it only works if I 'hard code' how many numbers I am checking. For example, if Y = 3, then my IF statement is checking l1[i], l1[i] + 1 and l1[i] + 2). I need it to work dynamically no matter what I set Y to.
Below is my code with my 'base logic':
A = [1,2,3,5,10,9,8,9,10,11,7,8,7]
new_indices = []
for index, number in enumerate(A[:-2]):
urgent_number = abs(A[index + 1])
next_number = abs(A[index + 2])
if (number + 1 == urgent_number and number + 2 == next_number) or (number - 1 == urgent_number and number - 2 == next_number):
new_indices.append(index)
print(new_indices)
Below is my attempt to try and incorporate a while loop to do this dynamically. I'm close, but I just can't seem to figure it out:
A = [1,2,3,5,10,9,8,9,10,11,7,8,7]
Y = 3 #length of list
new_indices = []
for index, number in enumerate(A[:-2]):
urgent_number = abs(A[index + 1])
next_number = abs(A[index + 2])
x = 0
while x < Y:
if (number + 1 == urgent_number and number + 2 == next_number) or (number - 1 == urgent_number and number - 2 == next_number):
new_indices.append(index)
x += 1
print(new_indices)
prints out [0,0,0,4,4,4,6,6,6,7,7,7]. However, I'm looking for [0,4,6,7].
Since you've gotten all the start indices and just need to remove the duplicates, you can do:
from itertools import groupby
original_result = [0,0,0,4,4,4,6,6,6,7,7,7]
final_result = [key for key, _ in groupby(original_result)]
[key for key, _ in groupby(original_result)]
to get the desired output.
This outputs:
[0, 4, 6, 7]
If you need to deal with variable run length specifically, you can find all the valid list slices that could make up a run, and then validate whether or not that slices makes up a run:
A = [1,2,3,5,10,9,8,9,10,11,7,8,7]
RUN_LENGTH = 3
indices = []
for s in range(len(A) - RUN_LENGTH):
is_incrementally_increasing = \
all(i2 - i1 == 1 for i1, i2 in zip(A[s:s+RUN_LENGTH], A[s+1:s+RUN_LENGTH]))
is_incrementally_decreasing = \
all(i1 - i2 == 1 for i1, i2 in zip(A[s:s+RUN_LENGTH], A[s+1:s+RUN_LENGTH]))
if is_incrementally_increasing or is_incrementally_decreasing:
indices.append(s)
print(indices)
This also outputs:
[0, 4, 6, 7]
This also works:
def dynamical(A):
new_indices = []
for index, number in enumerate(A[:-2]):
urgent_number = abs(A[index + 1])
next_number = abs(A[index + 2])
if (number + 1 == urgent_number and number + 2 == next_number) or (number - 1 == urgent_number and number - 2 == next_number):
new_indices.append(index)
return new_indices

Why does range in Python increments by 1 in the loop when performing calculation?

My Y[], Y1[] both have range(0, 8736). When running the code below, why does the range extend by 1 to range(0, 8737)?
diff = []
for i in range(len(Y)):
if(Y[i]==0):
diff.append(1)
if(Y1[i]==0):
diff.append(1)
else:
var = Y[i] / Y1[i]
diff.append(var)
print(range(len(diff)))
When i = 0 you append 1 twice, therefore len(diff) = len(Y) + 1 = len(Y1) + 1

Have a list of lists with each element a tuple. Prob. specifying specific tuple element

def distances(a, b):
"""Calculate edit distance from a to b"""
# declare matrix and set top left box to 0 and none
cost = [[(0,0) for x in range(len(a)+1)] for y in range(len(b)+1)]
cost[0][0] = (0, None)
# fill in first row
for i in range(1, len(a)+1):
cost[i][0] = (i, Operation.DELETED)
#fill in first column
for j in range(1, len(b)+1):
cost[0][j] = (j, Operation.INSERTED)
# fill in rest of the table from left to right, one row at a time
i = 1
j = 1
while i < len(a) + 1:
while j < len(b) + 1:
if a[i-1] == b[j-1]:
cost[i][j] = (cost[i-1][j-1], Operation.SUBSTITUTED)
j += 1
else:
subcost = min(cost[i-1][j][0], cost[i][j-1][0], cost[i-1][j-1][0])
if subcost == cost[i-1][j][0]:
cost[i][j] = (cost[i-1][j][0] + 1, Operation.DELETED)
j += 1
elif subcost == cost[i][j-1][0]:
cost[i][j] = (cost[i][j-1][0] + 1, Operation.INSERTED)
j += 1
elif subcost == cost[i-1][j-1][0]:
cost[i][j] = (cost[i-1][j-1][0] + 1, Operation.SUBSTITUTED)
j += 1
i += 1
j = 1
return cost
Gives me this error message:
TypeError: '<' not supported between instances of 'tuple' and 'int'
and specifies
subcost = min(cost[i-1][j][0], cost[i][j-1][0], cost[i-1][j-1][0])
as the problem line
Each cost[i][j][0] should be specifying the first element of the jth tuple in the ith list of cost, which should be an int, yet it's saying they're tuples and I don't get why.

IndexError: list index out of range in Python for function

I tried looking on this site but i can't find exactly what's going wrong with my program. It makes it all the way to 13 or the data_list[25] but then it spits out that IndexError message.
def rlEncode(n, z, data_list):
while data_list[n] == data_list[n+1]:
z = z + 1
n = n + 1
while data_list[n] != data_list[n+1]:
return (n, z)
def unitTest( ):
counter = 0
n = 0
z = 1
data_list = [1,1,1,1,1,3,3,5,5,5,5,5,5,6,8,8,1,1,1,5,5,5,5,13,14, 14]
compress_list = [ ]
while counter < len(data_list):
rlEncode(n, z, data_list)
x, y = rlEncode(n, z, data_list)
compress = [data_list[x], y]
counter = counter + 1
compress_list = compress_list + compress
n = x+1
z = 1
continue
print("list: ", data_list)
print("compressed: ", compress_list)
In your rlEncode function, you are checking the while condition after incrementing n too high:
def rlEncode(n, z, data_list):
while data_list[n] == data_list[n+1]:
z = z + 1
n = n + 1
The first time you check data_list[n] == data_list[n + 1] it's ok ... but then you do n = n + 1, and go back to check the while condition. At this point, if n is 25, data_list[n + 1] will give you an index error, because data_list[25 + 1] does not exist.
You can check this by adding a print line like print(n, len(data_list)) just after n = n + 1.
So either make sure you only iterate from 0 to 24, or make sure you do something like:
if n == len(data_list) - 1:
break
You always have to keep the upper bounds of your arrays in mind when you are doing things like list[n + 1] anywhere in your algorithm.
Spoilers: Solution below:
In order to get your code working, I made two changes:
def rlEncode(n, z, data_list):
# Make sure we don't overrun our list length:
while n < len(data_list) - 1 and data_list[n] == data_list[n + 1]:
z += 1
n += 1
return (n, z)
def unitTest( ):
counter = 0
n = 0
z = 1
data_list = [1,1,1,1,1,3,3,5,5,5,5,5,5,6,8,8,1,1,1,5,5,5,5,13,14,14]
compress_list = []
while n < len(data_list) - 1: # Use n here, not counter
rlEncode(n, z, data_list)
x, y = rlEncode(n, z, data_list)
compress = [data_list[x], y]
counter = counter + 1
compress_list = compress_list + compress
n = x + 1
z = 1
print("list: ", data_list)
print("compressed: ", compress_list)
unitTest()
('list: ', [1,1,1,1,1, 3,3, 5,5,5,5,5,5, 6, 8,8, 1,1,1, 5,5,5,5, 13, 14,14])
('compressed: ', [1,5, 3,2, 5,6, 6,1, 8,2, 1,3, 5,4, 13,1, 14,2])

Categories

Resources