Converting repetitive if statements into a loop - python

I have this code:
#!/usr/bin/python3
def contract(e, i, c, n):
l = len(e)
grid = [[0 for i in range(i + 1)] for x in range(l)]
for num1, row1 in enumerate(grid):
row1[0] = e[num1] #add exponents
for num2, row2 in enumerate(grid):
if 0 <= num2 < n[0]:
grid[num2][1] = c[num2]
if n[0] <= num2 < n[0] + n[1]:
grid[num2][2] = c[num2]
if n[0] + n[1] <= num2 < n[0] + n[1] + n[2]:
grid[num2][3] = c[num2]
for g in grid:
print(g)
e = [0, 1, 2, 3]
i = 3
c = [4, 5, 6, 7]
n = [1, 2, 1]
contract(e, i, c, n)
The idea of this code is that I have a 2 dimensional grid that has dimensions len(e) x (i + 1). The first column contains exponents e. The rest of the columns should contain coefficients c in such a way that n determines the positions of the coefficients in the grid. For example, since n[0] = 1, column 1, row 0 in the grid contains number 4. The next element in n is 2, so the next column in the grid (column 2) should contain 2 numbers, meaning numbers 5 and 6 in rows below the row that I used previously (meaning rows 1 and 2 because row 0 is already used). n[2] = 1 so grid[3][3] = 7, etc.
I implemented this with repetitive if-statements and the code works fine, the output is as it should be:
[0, 4, 0, 0]
[1, 0, 5, 0]
[2, 0, 6, 0]
[3, 0, 0, 7]
However, I would like to make an extensible program that can do this for any number of coefficients and exponents. How can I convert those repetitive if statements to a single loop?

I would convert it into a for loop that keeps track of the sum of the elements seen so far, adjusting the corresponding element if the inequality holds for that iteration:
for num2, row2 in enumerate(grid):
total = 0
for n_idx, n_elem in enumerate(n):
if total <= num2 < total + n_elem:
grid[num2][n_idx + 1] = c[num2]
total += n_elem
I would advise against using sum() in this loop, as it recomputes the sum from scratch on each iteration, which isn't very efficient.

Use a loop that sums successive slices of the n list.
for num2, row2 in enumerate(grid):
for idx in range(len(n)):
if sum(n[:idx]) <= num2 < sum(n[:idx+1]):
grid[num2][idx+1] = c[num2]
This is a direct mapping of the code you wrote to a loop, and reasonable if n doesn't get too large. BrokenBenchmark's answer is optimized to take advantage of the fact that the sum of each slice is the sum of the previous slice plus the current element.

Related

Cut a sequence of length N into subsequences such that the sum of each subarray is less than M and the cut minimizes the sum of max of each part

Given an integer array sequence a_n of length N, cut the sequence into several parts such that every one of which is a consequtive subsequence of the original sequence.
Every part must satisfy the following:
The sum of each part is not greater than a given integer M
Find a cut that minimizes the sum of the maximum integer of each part
For example:
input : n = 8, m = 17 arr = [2, 2, 2, 8, 1, 8, 2, 1]
output = 12
explanation: subarrays = [2, 2, 2], [8, 1, 8], [2, 1]
sum = 2 + 8 + 2 = 12
0 <= N <= 100000
each integer is between 0 and 1000000
If no such cut exists, return -1
I believe this is a dynamic programming question, but I am not sure how to approach this.
I am relatively new to coding, and came across this question in an interview which I could not do. I would like to know how to solve it for future reference.
Heres what I tried:
n = 8
m = 17
arr = [2, 2, 2, 8, 1, 8, 2, 1]
biggest_sum, i = 0, 0
while (i < len(arr)):
seq_sum = 0
biggest_in_seq = -1
while (seq_sum <= m and i < len(arr)):
if (seq_sum + arr[i] <= m ):
seq_sum += arr[i]
if (arr[i] > biggest_in_seq):
biggest_in_seq = arr[i]
i += 1
else:
break
biggest_sum += biggest_in_seq
if (biggest_sum == 0):
print(-1)
else:
print(biggest_sum)
This givens the result 16, and the subsequences are: [[2, 2, 2, 8, 1], [8, 2, 1]]
Problem is that you are filling every sequence from left to right up to the maximum allowed value m. You should evaluate different options of sequence lengths and minimize the result, which in the example means that the 2 8 values must be in the same sequence.
a possible solution could be:
n = 8
m = 17
arr = [2, 2, 2, 8, 1, 8, 2, 1]
def find_solution(arr, m, n):
if max(arr)>m:
return -1
optimal_seq_length = [0] * n
optimal_max_sum = [0] * n
for seq_start in reversed(range(n)):
seq_len = 0
seq_sum = 0
seq_max = 0
while True:
seq_len += 1
seq_end = seq_start + seq_len
if seq_end > n:
break
last_value_in_seq = arr[seq_end - 1]
seq_sum += last_value_in_seq
if seq_sum > m:
break
seq_max = max(seq_max, last_value_in_seq)
max_sum_from_next_seq_on = 0 if seq_end >= n else optimal_max_sum[seq_end]
max_sum = max_sum_from_next_seq_on + seq_max
if seq_len == 1 or max_sum < optimal_max_sum[seq_start]:
optimal_max_sum[seq_start] = max_sum
optimal_seq_length[seq_start] = seq_len
# create solution list of lists
solution = []
seg_start = 0
while seg_start < n:
seg_length = optimal_seq_length[seg_start]
solution.append(arr[seg_start:seg_start+seg_length])
seg_start += seg_length
return solution
print(find_solution(arr, m, n))
# [[2, 2, 2], [8, 1, 8], [2, 1]]
Key aspects of my proposal:
start from a small array (only last element), and make the problem array grow to the front:
[1]
[2, 1]
[8, 2, 1]
etc.
for each of above problem arrays, store:
the optimal sum of the maximum of each sequence (optimal_max_sum), which is the value to be minimized
the sequence length of the first sequence (optimal_seq_length) to achieve this optimal value
do this by: for each allowed sequence length starting at the beginning of the problem array:
calculate the new max_sum value and add it to previously calculated optimal_max_sum for the part after this sequence
keep the smallest max_sum, store it in optimal_max_sum and the associated seq_length in optimal_seq_length

Row reducing a matrix (not using sympy.rref)

I have a matrix, G (size PxN), and I would like to make the first N/2 columns of G form the N/2×N/2 identity matrix by row operations. Any idea how I could write code for this? (not using sympy.rref).
Note P is a prime number slightly larger than N.
The matrix itself is a vandermonde matrix over the field of P i.e. all values are modulo P.
def ReedSolomon(k,p):
rr = np.arange(k).reshape((-1, 1))
cc = np.arange(p)
return cc**rr % p
An example would be:
ReedSolomon(4,5)
= [[1, 1, 1, 1, 1],
[0, 1, 2, 3, 4],
[0, 1, 4, 4, 1],
[0, 1, 3, 2, 4]]
And i would like to produce the following:
= [[1, 0, -1, -2, -3],
[0, 1, 2, 3, 4],
[0, 1, 4, 4, 1],
[0, 1, 3, 2, 4]]
In this case the N/2 x N/2 submatrix is the identity.
Using sympy.rref would lead to some rows being swapped around and for more rows to be reduced. I would like to stop once the N/2 columns have been turned into the identity. Hence writing custom code is preferred.
Thanks!
The following code works (adapted from: python built-in function to do matrix reduction)
def rref(V, tol = 1.0e-12):
m, n = V.shape
i, j = 0, 0
jb = []
while i < (n//2) and j < (n//2):
# Find value and index of largest element in the remainder of column j
k = np.argmax(np.abs(V[i:n, j])) + i
p = np.abs(V[k, j])
if p <= tol:
# The column is negligible, zero it out
V[i:n//2, j] = 0.0
j += 1
else:
# Remember the column index
jb.append(j)
if i != k:
# Do not swap the i-th and k-th rows
pass
# Divide the pivot row i by the pivot element A[i, j]
V[i, j:n] = V[i, j:n] / V[i, j]
# Subtract multiples of the pivot row from all the other rows
for k in range(n//2):
if k != i:
V[k, j:n] -= V[k, j] * V[i, j:n]
i += 1
j += 1
return V
The adaptations include removing any row switching capability and limiting to the first n//2 columns and rows.
If anybody knows a more efficient way please let me know. Thanks

Printing given pattern using for loop

I have written the following code and it runs but I am using 4 for loops and I would like to know if there is more effective way to write this code.
n = int(input('Please Enter the highest number \n'))
col = 2*n-1
for i in range(1, n+1):
for j in range(1, col+1):
if j >= i and j <= col-i+1:
print(n-i+1, end=' ')
elif j < i:
print(n+1-j, end=' ')
else:
print(j+1-n, end=' ')
print()
for i in range(n-1, 0, -1):
for j in range(1, col+1):
if j >= i and j <= col - i + 1:
print(n-i+1, end=' ')
elif j < i:
print(n + 1 - j, end=' ')
else:
print(j + 1 - n, end=' ')
print()
You could find the position relative to the center (di, dj), and then use its largest component as the label for that cell:
n = int(input('Please Enter the highest number \n'))
col = 2 * n
for i in range(1, col):
row = []
for j in range(1, col):
di, dj = abs(n-i), abs(n-j)
row.append(max(di,dj) + 1)
print(' '.join(str(x) for x in row))
Problem Definition
Breaking this down into a few logical obsevations.
We have a grid of numbers that appears symmetrical.
However, the middle row / middle column are only repeated once, this is
important.
Therefore it is more similar to looking down on a pyramid
from above, where 1 represents the highest point, and 4 / n the
lowest.
So we know that to follow DRY principle, we only need to generate one corner of the pyramid, and then we simply copy it to the other 3 corners.
Solution
(assuming use of pure python 3.x only, without libraries such as numpy)
def print_pyramid(n=4):
"""Print a symmetrical pyramid of numbers descending from n"""
# Calculate bottom half of grid
bottom = []
for j in range(n):
row = [max(i, j + 1) for i in range(1, n + 1)]
row = row[::-1][:-1] + row
bottom.append(row)
# Invert bottom to get top
rows = bottom[::-1][:-1] + bottom
# Print formatted
for row in rows:
row_str = [str(i) for i in row]
print(f"{' '.join(row_str)}")
print_pyramid(4)
This is definitely not the most efficient method (see recursive functions), but it is fairly quick and pythonic.
Explanation
Bottom Right corner
First we generate an array of numbers, 1 => n:
[i for i in range(1, n + 1)]
[1, 2, 3, 4]
Then we loop n times to generate this for each row (j), but replace any values lower than j using max:
for j in range(n):
row = [max(i, j+1) for i in range(1,n+1)]
[1, 2, 3, 4]
[2, 2, 3, 4]
[3, 3, 3, 4]
[4, 4, 4, 4]
Bottom Left Corner (~mirror image)
First we select the row elements in reverse with slice notation [::-1]
Then we remove the last element [:-1]
row = [max(i, j+1) for i in range(1,n+1)]
row[::-1][:-1]
[4, 3, 2]
[4, 3, 2]
[4, 3, 3]
[4, 4, 4]
Top Half
Now we create the top half using the same slicing technique to reverse and select from our existing nested array.
bottom[::-1][:-1]
[4, 4, 4, 4, 4, 4, 4]
[4, 3, 3, 3, 3, 3, 4]
[4, 3, 2, 2, 2, 3, 4]
Finally, we print our full array with string formatting
for row in rows:
row_str = [str(i) for i in row]
print(f"{' '.join(row_str)}")
4 4 4 4 4 4 4
4 3 3 3 3 3 4
4 3 2 2 2 3 4
4 3 2 1 2 3 4
4 3 2 2 2 3 4
4 3 3 3 3 3 4
4 4 4 4 4 4 4
P.S. Please don't cheat on your homework assignments ;)
Since the inner loops are identical, you could join the two outer loops into one, e.g. by chaining the two ranges:
from itertools import chain
...
for i in chain(range(1, n + 1), range(n - 1, 0, -1)):
...
The condition can be simplified like this:
i <= j <= col - i + 1

Python: printing 1 row of Pascal Triangle

New to learning python and am having some trouble understanding a solution provided?
It has to do with Pascal Triangle and printing the rows when asking a user to "enter a row number"
There were bits of the solution provided and the rest I fit in (first for loop)..
n=int(input("Enter a row number: "))
a=[]
for i in range(n):
a.append([])
a[i].append(1)
for j in range(1,i):
a[i].append(a[i-1][j-1]+a[i-1][j])
if(n!=0):
a[i].append(1)
for i in range(n):
print(" "*(n-i),end=" ",sep=" ")
for j in range(0,i+1):
print('{:4}'.format(a[i][j]),end=" ")
print()
My question is which part of the code is printing the triangle structure? I assume the last for loop?
Also if I wanted to just print 1 row, what would I be changing?
EX: Input: 5 and output would be [1 4 6 4 1 ]
Thank you and any help/advice would be appreciated
You are right, the last loop is printing every row of the triangle. To print any specific row, jut run the second loop with specific value of i.
Before that, there is an easier way to more forward. Let's consider the output of below code:
n = 7
a = []
for i in range(n):
a.append([])
a[i].append(1)
for j in range(1, i):
a[i].append(a[i - 1][j - 1] + a[i - 1][j])
if (n != 0):
a[i].append(1)
print(a)
The output is:
[[1, 1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1], [1, 5, 10, 10, 5, 1], [1, 6, 15, 20, 15, 6, 1]]
From this 2d array, you can decide which single element you want to print. For example at index 4 you have [1, 4, 6, 4, 1]. From these values in the array a you can figure out which row to print.
Now for 5 if you want [1, 4, 6, 4, 1], you can simply do the following:
n = 7
a = []
for i in range(n):
a.append([])
a[i].append(1)
for j in range(1, i):
a[i].append(a[i - 1][j - 1] + a[i - 1][j])
if (n != 0):
a[i].append(1)
to_print = 5
for i in range(0, len(a[to_print-1])):
print(a[to_print-1][i], end=" ")
The output will be:
1 4 6 4 1
#riam_98, would you like to try this version: It's simplified the logic/flow to take advantage of Pascal key characteristics.
More reading can be found here - https://en.wikipedia.org/wiki/Pascal's_triangle
from typing import List
def getRow(index: int) -> List[int]:
row = [1] # firsts row
if index == 1: return row
for i in range(index-1):
for j in range(i, 0, -1):
row[j] = row[j] + row[j-1]
row.append(1)
return row
print(getRow(2))
print(getRow(3))
print(getRow(4))
print(getRow(5))
Outputs:
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1] # 5th
if I wanted to just print 1 row, what would I be changing?
I believe the answers given (and accepted) so far do too much work to obtain the values for an individual row. If we look at Calculating a row or diagonal by itself in the Wikipedia page that #DanielHao recommends, we can generate a simpler solution:
n = int(input("Enter a row number: "))
numbers = [1]
for k in range(1, n):
numbers.append(numbers[-1] * (n - k) // k)
print(numbers)
We don't need to generate the entire triangle up to the row we desire nor use nested loops to calculate it.
OUTPUT
> python3 test.py
Enter a row number: 5
[1, 4, 6, 4, 1]
> python3 test.py
Enter a row number: 10
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
>
which part of the code is printing the triangle structure? I assume
the last for loop?
Yes, but note that it is a fragile, limited solution due to the hardcoding of the number width:
print('{:4}'.format(a[i][j]),end=" ")
For smaller values, the triangle is lopsided, and for values larger than 16, it loses all its symmetry. Here's an example of a Pascal's triangle output that self adjusts Compare it's output to the solution you're asking about.

How to process matrix multiplication in python?

this program will get the basic informations one by one(input row, column, row, column)
then the numbers(numbers in first matrix orderd by column, in second, ordered by row)
so, if the first matrix like this will be listed as A.[1,2,3,4]
1 2
3 4
and the second one will be B.[5,7,6,8]
5 6
7 8
and I made number of row of first matrix as num1 of column as num2
row of second matrix as num3 (num3 should equal to num2 to calculate) of column as num4
its result will be like this no matter how big of the matrices
A[0]*B[0]+A[1]*B[1] A[0]*B[2]+A[1]*B[3]
A[2]*B[0]+A[3]*B[1] A[2]*B[2]+A[3]*B[3]
so I have to code this where I'm stuck in :
while j in B(j) increases until j reaches `(num3*num4-1)`,
i in A(i) should increase and repeat the interval(0, num2-1)
so result will be res += int(A[i]) * int(B[j])
when j reaches (num3*num4-1), it should go back to 0 and repeat these process until i reaches (num1*num2-1)
if num2 == num3:
res=0
for k in range(0, num2):
for i in range(k, ):
for l in range(0, (num4)-1):
for j in range(l*num2, (l+1)*(num2)-1):
res += int(a[i])*int(b[j])
c.append(res)
k+=1
Matrix multiplication can be done easily using NumPy package.
a = [[1, 0], [0, 1]]
b = [[4, 1], [2, 2]]
np.matmul(a, b)
The result of multiplication would be an Array.
array([[4, 1],[2, 2]])
If you want to do it old for loop way then iterating through columns and rows to multiply and then adding values will result in matrix multiplication as in below code.
# Program to multiply two matrices using nested loops
# 2 * 2 matrix
X = [[1, 2],
[3, 4]]
# 2 * 2 matrix
Y = [[5,6],
[7,8]]
# result is 2 * 2
result = [[0,0,],
[0,0,]]
# iterate through rows of X
for i in range(len(X)):
# iterate through columns of Y
for j in range(len(Y[0])):
# iterate through rows of Y
for k in range(len(Y)):
result[i][j] += X[i][k] * Y[k][j]
for r in result:
print(r)
Result will be
[19, 22]
[43, 50]
You can try the following
import numpy
def matrix_multiplier(auxA, auxB):
print (numpy.matmul(auxA,auxB))
#[1, 2]
#[3, 4]
auxA = numpy.array([[A[0], A[1]],[A[2], A[3]]])
#[5, 6]
#[7, 8]
auxB = numpy.array([B[0], B[1]],[B[2], B[3]])
matrix_multiplier(auxA,auxB)
Which gives the result:
[[19 22]
[43 50]]
This is an implementation that keeps the inputs in a flat array structure as you initially intended. It could be a good idea to check not only that num2 == num3 but also that len(a) % num2 == 0 and that len(b) % num3 == 0
c = []
for k in range(0, len (a)/num2):
for i in range(0, len (b)/num3):
res = 0
for n in range(0,num2):
j = num3*i + n
l = num2*k + n
res += int(a[l]*b[j])
if n == num2-1:
c.append(res)

Categories