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
Related
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.
arr = [1, 2, 3, 4, 5, 6]
for i in range(1, 6):
arr[i - 1] = arr[i]
for i in range(0, 6):
print(arr[i], end = " ")
Answer is :2 3 4 5 6 6
This is your code:
arr = [1, 2, 3, 4, 5, 6]
for i in range(1, 6):
arr[i - 1] = arr[i]
for i in range(0, 6):
print(arr[i], end = " ")
arr is a list comprised of 6 integers.
In your first for loop, i will vary from 1 to 5 (inclusive).
Python lists are accessed using base-0 - i.e., the first element is at index zero, the second at 1 and so on.
Therefore your loop is moving every element to the position (index) that immediately precedes it. Nothing is moved into index 5
if you are refering to get the following result : 2 3 4 5 6 1
then you should rearrange the following way:
for i in range(0, 6):
arr[i-1] = arr[i]
that way, you start with arr[-1] = arr[0], so 6 will be replaced with 1 and so the code goes on
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.
I'm trying to find how many arrangements of a list are possible with each arrangement 'fitting' into another list (i.e. all elements of the arrangement have to be less than or equal to the corresponding element). For example, the list [1, 2, 3, 4] has to fit in the list [2, 4, 3, 4].
There are 8 possible arrangements in this case:
[1, 2, 3, 4]
[1, 4, 2, 3]
[1, 3, 2, 4]
[1, 4, 3, 2]
[2, 1, 3, 4]
[2, 4, 1, 3]
[2, 3, 1, 4]
[2, 4, 3, 1]
Because 3 and 4 cannot fit into the first slot of the list, all arrangements that start with 3 or 4 are cut out. Additionally, 4 cannot fit into the third slot, so any remaining arrangements with 4 in the third slot are removed.
This is my current code trying to brute-force the problem:
from itertools import permutations
x = [1, 2, 3, 4]
box = [2, 4, 3, 4] # this is the list we need to fit our arrangements into
counter = 0
for permutation in permutations(x):
foo = True
for i in range(len(permutation)):
if permutation[i] > box[i]:
foo = False
break
if foo:
counter += 1
print(counter)
It works, but because I'm generating all the possible permutations of the first list, it's very slow, but I just can't find an algorithm for it. I realize that it's a basically a math problem, but I'm bad at math.
If you sort the x in reverse, you can try to find all the spots each element can fit in the box one at a time.
In your example:
4 has 2 spots it can go
3 has 3 spots, but you have to account for already placing the "4",
so you have 3 - 1 = 2 available
2 has 4 spots, but you have to account for already placing two things
(the "4" and "3"), so you have 4 - 2 = 2 available
1 has 4 spots, but you have already placed 3... so 4 - 3 = 1
The product 2 * 2 * 2 * 1 is 8.
Here's one way you can do that:
import numpy as np
counter = 1
for i, val in enumerate(reversed(sorted(x))):
counter *= ( (val <= np.array(box)).sum() - i)
print(counter)
...or without numpy (and faster, actually):
for i, val in enumerate(reversed(sorted(x))):
counter *= ( sum( ( val <= boxval for boxval in box)) - i)
I've experimented a bit with timings and here's what I found:
Your original code
for permutation in permutations(x):
foo = True
for i in range(len(permutation)):
if permutation[i] > box[i]:
foo = False
break
if foo:
counter += 1
Took about 13569 ns per run
Filtering the permutation
for i in range(100):
res = len(list(filter(lambda perm: all([perm[i] <= box[i] for i in range(len(box))]), permutations(x))))
Took slightly longer at 16717 ns
Rick M
counter = 1
for i, val in enumerate(reversed(sorted(x))):
counter *= ((val <= np.array(box)).sum() - i)
Took even longer at 20146 ns
Recursive Listcomprehension
def findPossiblities(possibleValues, box):
return not box or sum([findPossiblities([rem for rem in possibleValues if rem != val], box[1:]) for val in [val for val in possibleValues if val <= box[0]]])
findPossiblities(x, box)
Even longer at 27052 ns.
As a conclusion, using itertools and filtering is probably the best option
I'm trying to create a function equal to the sum of every other digit in a list. For example, if the list is [0,1,2,3,4,5], the function should equal 5+3+1. How could I do this? My knowledge of Python does not extend much farther than while and for loops. Thanks.
Here is a simple one-liner:
In [37]: L
Out[37]: [0, 1, 2, 3, 4, 5]
In [38]: sum(L[1::2])
Out[38]: 9
In the above code, L[1::2] says "get ever second element in L, starting at index 1"
Here is a way to do all the heavy lifting yourself:
L = [0, 1, 2, 3, 4, 5]
total = 0
for i in range(len(L)):
if i%2: # if this is an odd index
total += L[i]
Here's another way, using enumerate:
L = [0, 1, 2, 3, 4, 5]
total = 0
for i,num in enumerate(L):
if i%2:
total += num
>>> arr = [0,1,2,3,4,5]
>>> sum([x for idx, x in enumerate(arr) if idx%2 != 0])
9
This is just a list comprehension that only includes elements in arr that have an odd index.
To illustrate in a traditional for loop:
>>> my_sum = 0
>>> for idx, x in enumerate(arr):
... if idx % 2 != 0:
... my_sum += x
... print("%d was odd, so %d was added. Current sum is %d" % (idx, x, my_sum))
... else:
... print("%d was even, so %d was not added. Current sum is %d" % (idx, x, my_sum))
...
0 was even, so 0 was not added. Current sum is 0
1 was odd, so 1 was added. Current sum is 1
2 was even, so 2 was not added. Current sum is 1
3 was odd, so 3 was added. Current sum is 4
4 was even, so 4 was not added. Current sum is 4
5 was odd, so 5 was added. Current sum is 9
let's take this list as an example:
l = [1,2,3,4,5]
for even indexes sum:
even_index_eles = l[1::2] # [2, 4]
sum(even_index_eles) # 6
for odd indexes sum:
odd_index_eles = l[::2] # [1, 3, 5]
sum(odd_index_eles) # 9
it's worked with odd or even length of list