I made a program that allows the user to type in the height of a diamond and it will print one out in asterisks using loops. My code now looks like this:
diamond = int(input("Height": )
for i in range(diamond-1):
print((diamond-i) * " " + (2*i+1) * "*")
for i in range(diamond-1, -1, -1):
print((diamond - i) * " " + (2 * i + 1) * "*")
And the diamond will look perfect like this (diamond == 6):
*
***
*****
*******
*********
***********
*********
*******
*****
***
*
Now if I make some changes and instead write the backwards loop like this:
for i in reversed(range(diamond-1)):
print((diamond - i) * " " + (2 * i + 1) * "*")
It will print out the diamond like this:
*
***
*****
*******
*********
*********
*******
*****
***
*
So my question is: what is the difference between the first backwards loop and the second one I wrote? Why do they turn out so different?
Because they are different ranges:
>>> diamond = 6
>>> range(diamond-1, -1, -1)
[5, 4, 3, 2, 1, 0]
>>> list(reversed(range(diamond-1)))
[4, 3, 2, 1, 0]
range includes the start point, but excludes the end point.
Related
this is a part of my program which generates * patterns from 4 user inputs
total= progresscount + trailercount + retrivercount + excludecount
print("....................................................")
print("Histogram")
print("Progress",progresscount,":" , "*" * progresscount)
print("Trailer",trailercount,":" , "*" * trailercount)
print("Retriver",retrivercount,":" , "*" * retrivercount)
print("Excluded",excludecount ,":" , "*" * excludecount )
print("....................................................")
if I run my whole program and enter 2 3 1 and 2 for each input requests, output looks like this
....................................................
Histogram
Progress 2 : **
Trailer 3 : ***
Retriver 1 : *
Excluded 2 : **
....................................................
and I want to make a vertical version like this
....................................................
Progress Trailing Retriever Excluded
* * * *
* * *
*
....................................................
help me to figure this out?
You can create a custom function like below:
def display_vhist(data):
cell_len = max([len(k) for k in data]) + 2
max_val = max(data.values())
# display header
print(*[h.center(cell_len) for h in data.keys()], sep='')
# display histogram
for i in range(1, max_val+1):
for v in data.values():
c = '*' if i <= v else ' '
print(c.center(cell_len), end='')
print()
Usage:
data = {'Progress': 2, 'Trailer': 3, 'Retriver': 1, 'Excluded': 1}
display_vhist(data)
# Output
Progress Trailer Retriver Excluded
* * * *
* *
*
result1 = [prg_count,prg_mt_count,dnt_prg_count,excld_count]
total_students = prg_count + prg_mt_count + dnt_prg_count + excld_count
result2 = ["Progress", "Progress(MT)", "Do not Progress(MT)", "Exclude"]
def histogram (list1):
for i in range (len(list1)):
for j in range (list1[i]):
print("*",end="")
print("")
print('_' * 30)
print("Horizontal Histogram")
histogram (result1)
print(total_students, "outcomes in total")
print('_' * 30)
I want to print the items in the result2 list, one by one with their histogram value.
Histogram value changes according to user inputs and they're assigned to result1 list items.
what I'm trying to get;
Progress : *
Progress(MT) : *
Do not Progress(MT) : **
Excluded 1 : *
Did some improvements to your code, instead of loop for * printing I used '*' * count, same like you did for horizontal line '_' * 30, also printed names of histogram keys as you wished in your Question, plus used string's method .ljust(21) which adds extra spaces to align several strings to the same width.
Also as an example I showed histogram values 1, 5, 2, 3, see my Output after code below.
Try it online!
prg_count, prg_mt_count, dnt_prg_count, excld_count = 1, 5, 2, 3
result1 = [prg_count,prg_mt_count,dnt_prg_count,excld_count]
total_students = prg_count + prg_mt_count + dnt_prg_count + excld_count
result2 = ["Progress", "Progress(MT)", "Do not Progress(MT)", "Exclude"]
def histogram (list1, list2):
for a, b in zip(list1, list2):
print(b.ljust(21) + '*' * a)
print('=' * 30)
print("Horizontal Histogram")
print('-' * 30)
histogram(result1, result2)
print('-' * 30)
print(total_students, "outcomes in total")
print('=' * 30)
Output:
==============================
Horizontal Histogram
------------------------------
Progress *
Progress(MT) *****
Do not Progress(MT) **
Exclude ***
------------------------------
11 outcomes in total
==============================
Your question is not clear, but I think I know what you are saying. If you want to print the titles to the values (as I think your desired output says) you need to pass your titles in.
result1 = [5, 4, 2, 3]
total_students = sum(result1)
result2 = ["Progress","Progress(MT)","Do not Progress(MT)","Exclude"]
def histogram(result2, result1):
for i in range(len(result2)):
print(result2[i], end=" ")
for j in range(result1[i]):
print('*', end="")
print('')
print('_' * 30)
print("Horizontal Histogram")
histogram (result2, result1)
print(total_students, "outcomes in total")
print('_' * 30)
If you want to make it more succinct you can do this instead.
output = zip(result2, result1)
def histogram(list1):
for title, value in list1:
print(f"{title:20} {''.join(['*' for i in range(value)])}\n")
histogram(output)
I do need to create two recursive functions in Python. the first function should create a pyramid with a given parameter n. for example pyramid(3) should have the following output
*
***
*****
I came up with the following function:
def pyramid(n, i=0):
if n == 0:
return 0
else:
print(" "*(n-1) +"*"*(2*i+1)+ " "*(n-1))
return pyramid(n-1, i+1)
Now I do need to create a second recursive function pyramid_seq with 2 parameters n,k what prints a sequence of pyramids in with height of n. for example pyramid_seq(3,4) should have the following output:
* * * *
*** *** *** ***
********************
Add another parameter to your function (notice the changes in the recursive call) that determines how many times you should print every line. This will create the desired effect.
def pyramid(n, k, i=0):
if n == 0:
return 0
else:
print(k*(" "*(n-1) +"*"*(2*i+1)+ " "*(n-1)))
return pyramid(n-1, k, i+1)
Output for pyramid(4, 6):
* * * * * *
*** *** *** *** *** ***
***** ***** ***** ***** ***** *****
******************************************
If you want to properly leverage the power of recursion, your function should return their result as data and the printing part should be separate. This will allow you to reuse a previously defined function to produces new results from it:
def pyramid(h):
if h==1: return ["*"]
return [" "+p+" " for p in pyramid(h-1)]+["*"*(2*h-1)]
The function returns an array of lines (strings) that you can print or reuse for something else:
print(*pyramid(5),sep="\n")
*
***
*****
*******
*********
Because you now have a function that generates a pyramid as a list of lines, you can reuse it to concatenate its result to form a series of pyramids without reinventing the wheel:
def pyramids(h,w):
return [p*w for p in pyramid(h)]
print(*pyramids(4,6),sep="\n")
* * * * * *
*** *** *** *** *** ***
***** ***** ***** ***** ***** *****
******************************************
If your second function also needs to be recursive, you can still reuse the first one to build it:
def pyramids(h,w):
if w == 1: return pyramid(h)
return [ ps+p for ps,p in zip(pyramids(h,w-1),pyramid(h)) ]
Given a odd positive integer h, greater than or equal to 5, create a bowtie pattern with h rows and 2h columns.
input: 5
output:
* *
*** ***
**********
*** ***
* *
or
input: 7
output:
* *
*** ***
***** *****
**************
***** *****
*** ***
* *
I created code that only works for one given value of h but I'm not sure how to make it functional for any value of h. I also tried taking advantage of the symmetry so I made only half of the bowtie.
h = input()
n = int(h)
x = "*"
space = " "
print(x)
print(-(-n // 2)*x)
print(n*x)
print(-(-n // 2)*x)
print(x)
You can build up the top half by left and right justifying the * repeated as many times as necessary (we use range with a step for this as the first row will have 1 *, the next 2 more, the next 2 more again up until we reach N) padded left and right with width n, eg:
n = int(input())
top = [('*' * i).ljust(n) + ('*' * i).rjust(n) for i in range(1, n, 2)]
This gives you a top (for n=5) of:
['* *', '*** ***']
Then, we print the top, the middle (which is always * repeated N*2 times) and then top in reverse order for the bottom separated by newlines, eg:
print(*top, '*' * n * 2, *reversed(top), sep='\n')
Gives you (n=5):
* *
*** ***
**********
*** ***
* *
Or for (n=11):
* *
*** ***
***** *****
******* *******
********* *********
**********************
********* *********
******* *******
***** *****
*** ***
* *
Symmetry tells you that the left and the right have the same number of *. It also tells you that the middle row is all stars (n * 2), and that each row the same distance above and below the middle row has the same size. Further, as you move away from the center, you lose 4 stars total, 2 from each side.
The two secrets to coding this concise are to 1) number the rows symmetrical, not from 1 to n, but from -n//2 to n//2; and 2) to think of the rows as a number of spaces drawn on a background of *s, rather than a number of *s surrounding spaces.
Once you figure out how many spaces are in each row (call it f(i), based on the value of i in for i in range(-n//2, n//2+1): ..., you can draw that row with (" "*f(i)).center(2*n, "*").
it will work for any odd number
h = input()
n = int(h)
i = 1
if(n%2)!=0 and n > 4:
halfmark= n//2
str=""
while i <= n:
if(i<=halfmark):
blank = ' '* (4*(halfmark +1-i))
elif i > (halfmark+1):
blank = ' '*(4*(i-(halfmark+1)))
else:
blank = ''
star = '*'*((2*n-len(blank))//2)
str = star+blank+star
print(str)
i +=1
You may have noticed my last query on a similar task.
I am trying to replicate this structure:
********************
********* *********
******** ********
******* *******
****** ******
***** *****
**** ****
*** ***
** **
* *
** **
*** ***
**** ****
***** *****
****** ******
******* *******
******** ********
********* *********
********************
If you think of it as composed of 4 triangles - I am able to produce each of the corners individually, then to put them under one another.
I do not know how I would go about putting them together in a larger construct though.
Would I attempt this, or would I approach the problem by tackling it as if were a single construct and work on it line by line as I did with the individual triangle parts? I just assumed that the triangles into a bigger thing might be a shortcut.
This worked for me
w = 20
lines = []
for y in xrange(w / 2, 0, -1):
lines.append("".join(("*" * y, " " * (w - (y * 2)), "*" * y))
lines += reversed(lines[:-1])
for l in lines:
print l
You could shrink it down more if you wanted to as well:
lines = ["".join(("*" * y, " " * (w - (y * 2)), "*" * y)) for y in xrange(w / 2, 0, -1)]
print "\n".join(lines + lines[-2::-1])
Output w = 20:
********************
********* *********
******** ********
******* *******
****** ******
***** *****
**** ****
*** ***
** **
* *
** **
*** ***
**** ****
***** *****
****** ******
******* *******
******** ********
********* *********
********************
print '\n'.join('*' * (20 - i) + ' ' * (i * 2) + '*' * (20 - i) for i in range(0, 20))
print '\n'.join('*' * i + ' ' * (40 - i * 2) + '*' * i for i in range(0, 20))
http://codepad.org/Z46ldEOG
I would treat it as a different problem. If you imagine an origin at the centre of the figure, then you only want to print a * where the "Manhattan distance" to that cell is greater than half the length of the edge. For example, you could do the following:
import sys
r = 5
for y in range(-r,r+1):
for x in range(-r,r+1):
c = ' ' if (abs(x) + abs(y)) < r else '*'
sys.stdout.write(c)
print
... which produces this:
***********
***** *****
**** ****
*** ***
** **
* *
** **
*** ***
**** ****
***** *****
***********
How about:
W = 10
for i in range(10):
this_str = "*"*(W-i)+" "*i
print this_str+this_str[::-1]
for i in range(9,-1,-1):
this_str = "*"*(W-i)+" "*i
print this_str+this_str[::-1]
Peer pressure at work. Here's a shorter version to keep up with all my compatriots:
W=10
lines = ["*"*(W-i)+" "*2*i+"*"*(W-i) for i in range(W)]
print "\n".join(lines + lines[-2::-1])
If your instructor was looking for simple loops, this may help (even though its probably too late, and it only really works with even "w" value's)
w = 20
for a in range (0,w/2):
print((w/2-a)*"*"+2*a*" "+(w/2-a)*"*")
for a in range (2,w/2+1):
print(a*"*"+(w-2*a)*" "+a*"*")
Or if you wanted to take out the variable "w" all together:
for a in range (0,10):
print((10-a)*"*"+2*a*" "+(10-a)*"*")
for a in range (2,11):
print(a*"*"+(20-2*a)*" "+a*"*")