Python - Stacking Cups? - python

I have to write a function ('def stackHeights') where you are suppose to take an argument a number of cups, and returns the maximum height of a stack that can be built with that number of cups. For example if you have 7 cups, you can build the stack of height 3, but you don't have enough for a stack of height 4, because you only have one cup for the bottom row and you need 4.
"Hint: build from top to bottom using a while.
Output:
>>> stackHeight (7)
3
>>> stackHeight (3)
2
>>> stackHeight (12)
4
This is what I have right now:
def stackHeight(nCups):
nCups = int(input())
cups = {}
for i in range(nCups):
line = input().split()
if line[0].isnumeric():
cups[int(line[0])/2] = line[1]
else:
cups[int(line[1])] = line[0]
print("\n".join([cups[k] for k in sorted(cups.keys())]))
What am I doing wrong? The code doesn't seem to run for some reason. Keep in mind that I'm still fairly new to programming, so sorry for the cluster.

There are quite a few problems I notice with your code. First of all, you have input() way too many times, and input() will freeze the program whilst waiting for a user input. You probably want input("string that tells the user what to put here"). Also, you have a variable nCups, but nCups is being set to input(), so it is completely making the point of the variable useless. Also, if you want it how it is in your example, you don't want to print() in the loop. Another thing is that when you do cups={}, you are making it a dictionary, but you are later using an integer for the index, so you want a list [].

You're referring to a sequence of numbers called the Triangular Numbers, which has an equation to calculate the n-th number:
T(n) = n(n+1)/2
Using the quadratic formula you can invert this to:
T'(n) = (sqrt(8n+1)-1)/2
And thus your code will be:
def stackHeight(nCups):
return ((8*nCups+1)**0.5-1) // 2
And testing:
>>> def stackHeight(nCups):
... return ((8*nCups+1)**0.5-1)//2
...
>>> stackHeight(7)
3.0
>>> stackHeight(3)
2.0
>>> stackHeight(12)
4.0

Related

How the getattr() method works on this HackerRank case?

I recently began to learn programming.
During a HackerRank problem solving session, this one came up:
You are given a set A and N number of other sets. These N number of sets have to perform some specific mutation operations on set A.
Your task is to execute those operations and print the sum of elements from set A.
Here is a sample input (always in str format):
16 # number of elements on set A
1 2 3 4 5 6 7 8 9 10 11 12 13 14 24 52 # set A
4 # number of operations to realize on set A
intersection_update 10 # first input with operation and number of elements on the incoming set
2 3 5 6 8 9 1 4 7 11 # first set to realize operation on set A
update 2 # second input with operation and number of elements on the incoming set
55 66 # second set
The number of inputs is as big as N.
Here is my inefficient solution (1):
num_elem_a = int(input())
set_a = set(map(int, input().split()))
num_oper = int(input())
for i in range(0, num_oper):
entry = input().split()
if entry[0] == 'intersection_update':
set_a.intersection_update(set(map(int, input().split())))
elif entry[0] == 'update':
set_a.update(set(map(int, input().split())))
elif entry[0] == 'difference_update':
set_a.difference_update(set(map(int, input().split())))
elif entry[0] == 'symmetric_difference_update':
set_a.symmetric_difference_update(set(map(int, input().split())))
print(sum(set_a))
I am trying to learn how to code without all these "if's", and found a shorter and apparently cleverly solution (2):
(_, A) = (int(input()),set(map(int, input().split())))
B = int(input())
for _ in range(B):
(command, newSet) = (input().split()[0],set(map(int, input().split())))
getattr(A, command)(newSet)
print (sum(A))
Here is my doubt:
In my code (1) I had to call a method this way:
set_a.symmetric_difference_update(set(map(int, input().split())))
How is the getattr(A, command)(newSet) line doing the same job in (2)? I don't get the logic.
I understood which elements the command is calling, but I don't see how this command produces the same effect as my version in (1).
This question seems to be a duplicate, please refer to What is getattr() exactly and how do I use it?
Regarding your need to remove the "if's", please consider that, when working with other people, readibility is more important than unecessary if statements. For example, I could easily understand how the code sample (1), whilst code sample (2) is harder to read, besides that, you are opening doors to unwated code injections.
By this I mean that you are supposed to only apply specific permutation operations, which means that not all operations should be allowed. For example, you would not want the user to be able to call the set's clear method, which the code in solution (2) allows.
Of course this isn't a problem when working through code samples in HackerRank, just some food for thought to motivate your programming journey.

Shannon Diversity Program: basic questions

I am a biology student trying to get into programming and have some issue with a basic index calculator I am trying to write for a research project. I need a program that will prompt the user to input data points one at a time, perform the proper calculation (-1*(x*ln(x))) on each data point, and enter that new calculated value into an array. Once the user inputs 'done', I would like the program to sum the array values and return that index value.
This is what I have. I am very new so apologies for any blaring mistakes. Any points in the right direction are very appreciated.
import math
print('This program calculates a Shannon Diversity '
'Index value for a set of data points entered by the user.'
' when prompted enter a species number value,then press enter. '
'COntinue until all data points have been entered. '
'Upon completion, enter the word done.')
def Shannonindex():
index = []
entries = 1,000,000
endKey = 'done'
for i in range(entries):
index = [input("Enter a value: ")]
if index != endKey:
entry = p
p = -1*(x*ln(x))
index.append(p)
else Sindex = sum(index)
return Sindex
print('Your Shannon Diversity Value is: ", Sindex)
There are a huge number of problms here.
You need to get your variables straight.
You're trying to use index to mean both the list of values, and the input string. It can't mean both things at once.
You're trying to use x without defining it anywhere. Presumably it's supposed to be the float value of the input string? If so, you have to say that.
You're trying to use p to define entry before p even exists. But it's not clear what entry is even useful for, since you never use it.
You also need to get your control flow straight.
What code is supposed to run in that else case? Either it has to include the return, or you need some other way to break out of the loop.
You also need to get your types straight. [input(…)] is going to give you a list with one element, the input string. It's hard to imagine what that would be useful for. You can't compare that list to 'done', or convert it to a float. What you want is just the input string itself.
You can't just guess at what functions might exist. There's no function named ln. Look at the docs for Built-in Functions, the math module, and anything else that looks like it might be relevant to find the function you need.
1,000,000 is not a number, but a tuple of three numbers.
You can write 1_000_000, or just 1000000.
But it's not clear why you need a limit in the first place. Why not just loop forever until the enter done?
You've defined a function, but you never call it, so it doesn't do any good.
So, let's sort out these problems:
import math
def Shannonindex():
index = []
endKey = 'done'
while True:
value = input("Enter a value: ")
if value != endKey:
x = float(value)
p = -1 * (x * math.log(x))
index.append(p)
else:
Sindex = sum(index)
return Sindex
Sindex = Shannonindex()
print('Your Shannon Diversity Value is: ", Sindex)
There are still many ways you could improve this:
Add some error handling, so if the user typos 13.2.4 or 1O, it tells them to try again instead of bailing out on the whole thing.
You don't actually need to build a list, just keep a running total.
If you reverse the sense of the if/else it will probably be more readable.
You're not actually calculating the Shannon diversity index. That's not the sum of -x ln x, it's the sum of -p ln p where each p is the proportion of x / sum(all x). To handle that, you need to keep all the raw x values in a list, so you can convert that to a list of p values, so you can sum those.
import math
index = []
for i in range(1,100000):
val = input("Enter a value: ")
if val =='done':
break
else:
x = int(val)
p = -1*(x*math.log(x))
index.append(p)
print ("The value of index is %s:"%index)
=================================================
This is the simplified form of your code, since you are new to python.
This might help you get the values stored in a list and calculate it until you type done.

changing array element not work in python

I wrote a simple code in python for doing a sorting manually because I needed my labels to change according to the numbers too. However, swapping the elements seems to be not working. Am I forgetting something fundamental?
Here is my code:
h = np.array(prediction)
h = h.transpose()
t = np.array(Z.columns.values)
for l in range(0, h.size-3):
if h[0,l] < h[0, l+1]:
g = h[0, l]
h[0, l] = h[0, l+1]
h[0, l+1] = g
uu = t[l]
t[l] = t[l+1]
t[l+1] = uu
UPDATE 1:
Suppose that I have two arrays for demonstrating the number of cars in a parking and I want to sort it like to know which cars are more available in the parking. Both h and t are 1*N arrays. t holds the name of each car, for example, BMW', 'TOYOTA' and etc, and h holds the number of them for example 5,6 and etc. I want to sort the h array which is numbers and if an element has changed in the h, I want to change the name of relative cars in the other array too. It is a really simple thing for doing with other languages I know but because I am new in python I got into trouble. The interesting part is that code runs perfectly without error but the arrays don't change at all.
I don't fully understand your requirements, but at a glance, there are a bunch of assignments happening within that if, and none outside of it. If your arrays aren't changing my guess is that the code inside the if isn't executing, either because the test in the if is failing, or because range(0, h.size-3) is empty.
Stick some prints in there and see if that code is actually running!

Most minimal way to repeat things in python [duplicate]

This question already has answers here:
Is it possible to implement a Python for range loop without an iterator variable?
(15 answers)
Closed 7 months ago.
Suppose you want to write a program that asks the user for X numbers and store them in A, then for Y numbers and store them in B
BEFORE YOU VOTE FOR CLOSING : yes, this question has been asked here, here, here, here and possibly elsewhere, but I reply to each of the proposed solutions in this question explaining why they're not what I'm looking for, so please keep reading before voting for closing IF you decide it's a duplicate. This is a serious question, see last paragraph for a small selection of languages supporting the feature I'm trying to achieve here.
A = []
B = []
# First possibilty : using while loops
# you need to have a counter
i = 0
while (i < X):
A.append(input())
# and increment it yourself
i+=1
# you need to reset it
i = 0
while (i < Y):
B.append(input())
# and increment it again
i+=1
So basically you need to repeat a certain thing x times, then another Y times, but python has only while loops and for loops. The while loop is not to repeat a certain thing N times, but to repeat things while a certain condition is True, that's why you have to use a counter, initialize it, increment it, and test against it.
Second solution is to use for loops :
# No need to create a counter
for x in xrange(x):
A.append(input())
# No need to increment the counter
# no need to reset the counter
for x in xrange(Y):
B.append(input())
This is a lot better :), but there's still something slightly anoying : why would I still have to supply "x", when I don't need x ? In my code, I don't need to know in what loop iteration I am, i just need to repeat things N times, so why do I have to create a counter at all ? Isn't there a way to completely get rid of counters ? imagine you could write something like :
# No need to supply any variable !
repeat(x):
A.append(input())
repeat(Y):
B.append(input())
Wouldn't that be more elegant ? wouldn't that reflect more accurately your intention to possible readers of your code ? unfortunately, python isn't flexible enough to allow for creating new language constructs (more advanced languages allow this). So I still have to use either for or while to loop over things. With that restriction in mind, how do I get the most closer possible to the upper code ?
Here's what I tried
def repeat(limit):
if hasattr(repeat,"counter"):
repeat.counter += 1
return repeat.counter < limit
repeat.limit = limit
repeat.counters = 0
return limit > 0 and True
while repeat(x):
A.append(input())
while repeat(Y):
B.append(input())
This solution works for simple loops, but obviously not for nested loops.
My question is
Do you know any other possible implementation that would allow me to get the same interface as repeat ?
Rebbutal of suggested solutions
suggested solution 1.1 : use itertools.repeat
you'll have to place your code inside a function and call that function inside itertools.repeat, somehow. It's different from the above repeat implementation where you can use it over arbitrary indented blocks of code.
suggestion solution 1.2 : use itertools.repeat in a for loop
import itertools
for _ in itertools.repeat(None, N):
do_something()
you're still writing a for loop, and for loops need a variable (you're providing _), which completely misses the point, look again :
while repeat(5):
do_x()
do_y()
do_z()
Nothing is provided just for the sake of looping. This is what I would like to achieve.
suggested solution 2 : use itertools.count
1) you're half the way there. Yes, you get rid of manually incrementing the counter but you still need for a counter to be created manually. Example :
c = itertools.count(1,1) # You still need this line
while( c.next() < 7):
a = 1
b = 4
d = 59
print "haha"
# No need to increment anything, that's good.
# c.incr() or whatever that would be
You also need to reset the counter to 0, this I think could be hidden inside a function if you use the with statement on it, so that at every end of the with statement the counter gets reset.
suggested solution 3 : use a with statement
I have never used it, but from what I saw, it's used for sweeping the try/catch code inside another function. How can you use this to repeat things ? I'd be excited to learn how to use my first with statement :)
suggested solution 4 : use an iterator/generator, xrange, list comprehensions...
No, no, no...
If you write :
[X() for _ in xrange(4)]
you are :
1) creating a list for values you don't care about.
2) supplying a counter (_)
if you write :
for _ in xrange(4):
X()
see point 2) above
if you write :
def repeat(n):
i = 0
while i < n :
yield i < n
i+1
Then how are you supposed to use repeat ? like this ? :
for x in repeat(5):
X()
then see point 2) above. Also, this is basically xrange, so why not use xrange instead.
Any other cool ideas ?
Some people asked me what language do I come from, because they're not familiar with this repeat(N) syntax. My main programming language is python, but I'm sure I've seen this syntax in other languages. A visit of my bookmarks followed by online search shows that the following languages have this cool syntax :
Ruby
it's just called times instead of repeat.
#!/usr/bin/env ruby
3.times do
puts "This will be printed 3 times"
end
print "Enter a number: "
num = gets.chomp.to_i
num.times do
puts "Ruby is great!"
end
Netlogo
pd repeat 36 [ fd 1 rt 10 ]
;; the turtle draws a circle
AppleScript
[applescript]
repeat 3 times
--commands to repeat
end repeat
[/applescript]
Verilog
1 module repeat_example();
2 reg [3:0] opcode;
3 reg [15:0] data;
4 reg temp;
5
6 always # (opcode or data)
7 begin
8 if (opcode == 10) begin
9 // Perform rotate
10 repeat (8) begin
11 #1 temp = data[15];
12 data = data << 1;
13 data[0] = temp;
14 end
15 end
16 end
17 // Simple test code
18 initial begin
19 $display (" TEMP DATA");
20 $monitor (" %b %b ",temp, data);
21 #1 data = 18'hF0;
22 #1 opcode = 10;
23 #10 opcode = 0;
24 #1 $finish;
25 end
26
27 endmodule
Rebol
repeat count 50 [print rejoin ["This is loop #: " count]]
Forth
LABEL 10 0 DO something LOOP will repeat something 10 times, and you didn't have to supply a counter (Forth automatically stores it in a special variable I).
: TEST 10 0 DO CR ." Hello " LOOP ;
Groovy
you can either write 1.upTo(4){ code } or 4.times{ code } to execute code 4 times. Groovy is a blast when it comes to looping, it has like half a dozen ways to do it (upTo, times, step, java for, groovy for, foreach and while).
// Using int.upto(max).
0.upto(4, createResult)
assert '01234' == result
// Using int.times.
5.times(createResult)
assert '01234' == result
// Using int.step(to, increment).
0.step 5, 1, createResult
assert '01234' == result
WARNING: DO NOT DO THIS IN PRODUCTION!
I highly recommend you go with one of the many list comprehension solutions that have been offered, because those are infinitely less hacky. However, if you're adventurous and really, really, really want to do this, read on...
We can adapt your repeat solution slightly so that nesting works, by storing state that changes depending on where it's being called. How do we do that? By inspecting the stack, of course!
import inspect
state = {}
def repeat(limit):
s = tuple((frame, line) for frame, _, line, _, _, _ in inspect.stack()[1:])
counter = state.setdefault(s, 0)
if counter < limit:
state[s] += 1
return True
else:
del state[s]
return False
We set up a state dict to keep track of current counters for each unique place the repeat function is called, by keying off of a tuple of (stack_frame, line_number) tuples. This has the same caveat as your original repeat function in that break literally breaks everything, but for the most part seems to work. Example:
while repeat(2):
print("foo")
while repeat(3):
print("bar")
Output:
foo
bar
bar
bar
foo
bar
bar
bar
Surely you are over-thinking things. If I understand your (rather lengthy) question correctly you want to avoid repeating code. In this case you first port of call should be to write a function. This seems relatively simple: what you need is a function that takes an argument x (I have used n simply because it reminds me of integers) and returns a list containing that many input elements. Something like (untested):
def read_inputs(n):
ret_val = []
for i in range(n):
ret_val.append(input())
return retval
The remainder of your code is simply:
A = read_inputs(X)
B = read_inputs(Y)

Can Python generate a random number that excludes a set of numbers, without using recursion?

I looked over Python Docs (I may have misunderstood), but I didn't see that there was a way to do this (look below) without calling a recursive function.
What I'd like to do is generate a random value which excludes values in the middle.
In other words,
Let's imagine I wanted X to be a random number that's not in
range(a - b, a + b)
Can I do this on the first pass,
or
1. Do I have to constantly generate a number,
2. Check if in range(),
3. Wash rinse ?
As for why I don't wish to write a recursive function,
1. it 'feels like' I should not have to
2. the set of numbers I'm doing this for could actually end up being quite large, and
... I hear stack overflows are bad, and I might just be being overly cautious in doing this.
I'm sure that there's a nice, Pythonic, non-recursive way to do it.
Generate one random number and map it onto your desired ranges of numbers.
If you wanted to generate an integer between 1-4 or 7-10, excluding 5 and 6, you might:
Generate a random integer in the range 1-8
If the random number is greater than 4, add 2 to the result.
The mapping becomes:
Random number: 1 2 3 4 5 6 7 8
Result: 1 2 3 4 7 8 9 10
Doing it this way, you never need to "re-roll". The above example is for integers, but it can also be applied to floats.
Use random.choice().
In this example, a is your lower bound, the range between b and c is skipped and d is your upper bound.
import random
numbers = range(a,b) + range(c,d)
r = random.choice(numbers)
A possible solution would be to just shift the random numbers out of that range. E.g.
def NormalWORange(a, b, sigma):
r = random.normalvariate(a,sigma)
if r < a:
return r-b
else:
return r+b
That would generate a normal distribution with a hole in the range (a-b,a+b).
Edit: If you want integers then you will need a little bit more work. If you want integers that are in the range [c,a-b] or [a+b,d] then the following should do the trick.
def RangeWORange(a, b, c, d):
r = random.randrange(c,d-2*b) # 2*b because two intervals of length b to exclude
if r >= a-b:
return r+2*b
else:
return r
I may have misunderstood your problem, but you can implement this without recursion
def rand(exclude):
r = None
while r in exclude or r is None:
r = random.randrange(1,10)
return r
rand([1,3,9])
though, you're still looping over results until you find new ones.
The fastest solution would be this (with a and b defining the exclusion zone and c and d the set of good answers including the exclusion zone):
offset = b - a
maximum = d - offset
result = random.randrange(c, maximum)
if result >= a:
result += offset
You still need some range, i.e., a min-max possible value excluding your middle values.
Why don't you first randomly pick which "half" of the range you want, then pick a random number in that range? E.g.:
def rand_not_in_range(a,b):
rangechoices = ((0,a-b-1),(a+b+1, 10000000))
# Pick a half
fromrange = random.choice(rangechoices)
# return int from that range
return random.randint(*fromrange)
Li-aung Yip's answer makes the recursion issue moot, but I have to point out that it's possible to do any degree of recursion without worrying about the stack. It's called "tail recursion". Python doesn't support tail recursion directly, because GvR thinks it's uncool:
http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html
But you can get around this:
http://paulbutler.org/archives/tail-recursion-in-python/
I find it interesting that stick thinks that recursion "feels wrong". In extremely function-oriented languages, such as Scheme, recursion is unavoidable. It allows you to do iteration without creating state variables, which the functional programming paradigm rigorously avoids.
http://www.pling.org.uk/cs/pop.html

Categories

Resources