I'm trying to solve this question:
We want to make a row of bricks that is goal inches long. We have a
number of small bricks (1 inch each) and big bricks (5 inches each).
Return True if it is possible to make the goal by choosing from the
given bricks. This is a little harder than it looks and can be done
without any loops.
make_bricks(3, 1, 8) → True
make_bricks(3, 1, 9) → False
make_bricks(3, 2, 10) → True
— codingbat.com
For that, I made this code:
def make_bricks(small, big, goal):
tam = small + big*5
ex_gran = goal - small
if goal <= small:
return True
elif ex_gran > big*5:
return False
elif ex_gran <= big * 5 and (ex_gran % 5 <= small) :
return True
else:
return False
And this is the result os the tests:
Expected Run
make_bricks(3, 1, 8) → True True OK
make_bricks(3, 1, 9) → False False OK
make_bricks(3, 2, 10) → True True OK
make_bricks(3, 2, 8) → True True OK
make_bricks(3, 2, 9) → False True X
make_bricks(6, 1, 11) → True True OK
make_bricks(6, 0, 11) → False False OK
make_bricks(1, 4, 11) → True True OK
make_bricks(0, 3, 10) → True True OK
make_bricks(1, 4, 12) → False True X
make_bricks(3, 1, 7) → True False X
make_bricks(1, 1, 7) → False False OK
make_bricks(2, 1, 7) → True True OK
make_bricks(7, 1, 11) → True True OK
make_bricks(7, 1, 8) → True True OK
make_bricks(7, 1, 13) → False False OK
make_bricks(43, 1, 46) → True True OK
make_bricks(40, 1, 46) → False False OK
make_bricks(40, 2, 47) → True True OK
make_bricks(40, 2, 50) → True True OK
make_bricks(40, 2, 52) → False False OK
make_bricks(22, 2, 33) → False False OK
make_bricks(0, 2, 10) → True True OK
make_bricks(1000000, 1000, 1000100) → True True OK
make_bricks(2, 1000000, 100003) → False True X
make_bricks(20, 0, 19) → True True OK
make_bricks(20, 0, 21) → False False OK
make_bricks(20, 4, 51) → False False OK
make_bricks(20, 4, 39) → True True OK
Only 4 of them was wrong, but I still can't figure it out the error.
What is wrong?
Try first to use as many big bricks as possible, then complete with the small ones. Note that this works because the size of the big ones is a multiple of the size of the small ones, you would need another approach if the sizes were for example 2 and 5.
def make_bricks(small, big, goal):
max_big = goal // 5 # max number of big we can use
nb_big = min(big, max_big) # big ones we really use
return small >= goal - 5 * nb_big # True if we have enough small ones to complete
Error is simple :) it lies on line 16. Although the code could be shorten a lot.
First if all, notice that condition ex_gran <= big * 5 is irrelevant since the conditional before was already false (elif ex_gran > big*5:) and we are assuming small, big and goal are all integers, so you can take that away from the code. (Althogh this is not what is bringing troubles to the code, that's more of a style remark).
Trouble is generated by this conditional: (ex_gran % 5 <= small).
As I understand, in the example make_bricks(1, 4, 12) your code returns True when it should return False. What happens is that the code checks whether (12 - 1) <= 4*5 which is True, and if (12 - 1) % 5 <= 1 which is also True and returns True in line 18 because of this.
Let's "fix" the code. Remember that from math we know there are integers m and r such that goal = 5*m + r (moreover r = goal % 5). After we know (goal-small) <= big*5 (from false evaluation in line 12) we have two cases:
Case 1: (goal - small) = big*5, which implies goal = big*5 + small and so we should return True.
Case 2: (goal - small) < big*5, then we know goal < big*5 + small. Here you should check whether (goal % 5) <= small. If this is false, then we can't arrange the bricks to obtain the goal length (since we don't have enough 1s to fill the residual, as in the example above). Otherwise, you should return True, since we have enough bricks to surpass the goal length and enough 1s to fill the residual.
Your code ends up looking like this (I took the liberty of renaming the variables):
def make_bricks(small_bricks, big_bricks, goal):
if ( (5*big_bricks + small_bricks) < goal ): #we can't reach the length
return False
elif (small_bricks < (goal%5)) : #we can surpass the length but we don't have
#enough 1s to fill goal's residual w.r.t. 5 div
return False
else: #We can reach the length and have enough 1s to fill residual
return True
notice I took away some case goal <= small as it's not needed here.
# This code works with those 3 tests but got some other one # wrong can some help fixed it?
def make_bricks(small, big, goal):
big = big * 5
if small == goal or big == goal:
return true
elif small + big == goal or big - small == goal:
return True
else:
return False
print(make_bricks(3, 1, 8)) # → True
print(make_bricks(3, 1, 9)) # → False
print(make_bricks(3, 2, 10)) # → True
This should work...
def make_bricks(small, big, goal):
total_bricks = (1 * small) + (5 * big)
if total_bricks >= goal:
if goal%5 == 0:
if goal/5 <= goal:
x = True
elif goal%5 <= small:
x = True
else:
x = False
else:
x = False
return x
This is probably not the most efficient way but it will work..
Probably Not the most Readable
def make_bricks(small, big, goal):
if (big is not 0 and (big*5+small*1 > goal) and goal % 5 <= small) or goal < small or big*5+small*1 == goal:
return True
else:
return False
def make_bricks(small, big, goal):
return small >= goal - 5*min(goal//5,big)
Before I ask my question, I provide you with the code.
Code
from scipy import *
x = randn(10)
cum_x = cumsum(x)
#The objective is to recover x using cum_x and the diff function.
y = append(cum_x[0],diff(cum_x))
#Now, y should be equal to x but this is not confirmed by the function in1d
test = in1d(x,y)
The variable test does not return an array of "True" boolean values even if y and x are clearly the same. What is the problem here?
Thank you in advance.
if you use set_printoptions to increase precision you will see some differences:
from scipy import *
set_printoptions(30)
x = randn(10)
cum_x = cumsum(x)
#The objective is to recover x using cum_x and the diff function.
y = append(cum_x[0], diff(cum_x))
print(x)
print("\n")
print(y)
#Now, y should be equal to x but this is not confirmed by the function in1d
test = in1d(x, y)
print(test)
Output:
[ 0.54816314147543721002620031868 0.14319052613251953554041051575
0.489110961092741158839913850898 -0.093011827554544138085823590245
-0.58370623188476589149331630324 -0.40395493550429123486011917521
0.387387395892057895263604905267 1.001637373359834937147638811439
-1.486778459872974744726548124163 1.446772274227251076084144187917]
[ 0.54816314147543721002620031868 0.143190526132519591051561747008
0.48911096109274110332876261964 -0.093011827554544179719187013688
-0.58370623188476589149331630324 -0.40395493550429123486011917521
0.387387395892057895263604905267 1.001637373359834937147638811439
-1.486778459872974744726548124163 1.446772274227251076084144187917]
[ True False False False True True True True True True]
What you probably want is allclose but interestingly setting the dtype to np.float128 or np.longdouble on my ubuntu system does not lose precision and in1d returns True.
cum_x = cumsum(x,dtype=np.longdouble)
My code should stop when all the values of my array are greater than 100. I am using np.all() to evaluate the condition. It looks like the condition is met, but np.all() seems to be incorrectly evaluating. What am I missing? Python 2.7.8 on OS 10.8.5.
(Pdb) ratio_J_a
array([ 250.44244741, 186.92848637, 202.67726408, 143.01112845,
132.95878384, 176.49130164, 178.9892571 , 118.07516559,
205.59639112, 183.64142204])
(Pdb) np.all(ratio_J_a) > 100.
False
(Pdb) np.all(ratio_J_a) < 100.
True
I think you should have:
In [5]: import numpy as np
In [6]: ratio_J_a = np.array([ 250.44244741, 186.92848637, 202.67726408, 143.01112845,
...: 132.95878384, 176.49130164, 178.9892571 , 118.07516559,
...: 205.59639112, 183.64142204])
In [7]: print(np.all(ratio_J_a > 100.))
True
In [8]: print(np.all(ratio_J_a < 100.))
False
And just in case, you are actually wondering why you got this:
(Pdb) np.all(ratio_J_a) > 100.
False
(Pdb) np.all(ratio_J_a) < 100.
True
The reason is that np.all(ratio_J_a) evaluates to true, which is treated as one, e.g.
In [17]: "{}".format(np.all(ratio_J_a))
Out[17]: 'True'
In [18]: "{:d}".format(np.all(ratio_J_a))
Out[18]: '1'
Thus, in your case you are actually doing this:
(Pdb) 1 > 100.
False
(Pdb) 1 < 100.
True
numpy.all tests whether all array elements along a given axis evaluate to True.
>>> import numpy as np
>>> ratio_J_a = np.array([
... 250.44244741, 186.92848637, 202.67726408, 143.01112845,
... 132.95878384, 176.49130164, 178.9892571 , 118.07516559,
... 205.59639112, 183.64142204
... ])
>>> np.all(ratio_J_a > 100)
True
>>> np.all(ratio_J_a < 100)
False
Why you got wrong result:
np.all(ratio_J_a) is evaluated as True because non-zero numbers are treated as a truth value. And True is equal to 1. 1 > 100 is False, 1 < 100 is True.
I went onto one line of code, which I want to convert from numpy syntax to regular python 2.7 syntax:
SunAz=SunAz + (SunAz < 0) * 360
source:
https://github.com/Sandia-Labs/PVLIB_Python/blob/master/pvlib/pvl_ephemeris.py#L147
If we pretend that the numpy array is one dimensional, can it be translated to regular python 2.7 syntax like so:
newSunAz = []
for item in SunAz:
if item < 0:
newItem = item + item*360
newSunAz.append(newItem)
else:
newSunAz.append(item)
??
Thank you for the help.
I'm not sure that this would be the translation. The line
SunAz=SunAz + (SunAz < 0) * 360
(SunAz < 0) creates a boolean array, True where the angle is negative, and false otherwise. Multiplying False by a constant gives 0, and True is interpreted to be a 1. This line actually says, "shift the angle by 360 degrees if negative, otherwise leave it be".
So a more literal translation would be the following:
SunAz = [angle + 360 if angle < 0 else angle for angle in SunAz]
Try this:
new_sun_az = [i+360 if i > 0 else i for i in sun_az]
The main difference is that most operators are applied to the list object in plain Python lists and return a single result, while they return a numpy array where each item is the result of the operation applied to the corresponding item on the original array for numpy arrays.
>>> import numpy as np
>>> plainlist = range(5)
>>> plainlist
[0, 1, 2, 3, 4]
>>> plainlist > 5 # single result
True
>>> nparray = np.array(plainlist)
>>> nparray
array([0, 1, 2, 3, 4])
>>> nparray > 5 # array of results
array([False, False, False, False, False], dtype=bool)
>>>
[update]
Mike's answer is right. My original answer was:
new_sun_az = [i+i*360 if i > 0 else i for i in sun_az]
>>> import numpy
>>> numpy.array([2]) > 1
array([ True], dtype=bool)
>>> numpy.array([2]).any() > 1
False
Shouldn't any() test all elements of the array and return True?
It does return True. But (True > 1) == False. While the first part is 2 > 1 which of course is True.
As others posted, you probably want:
(numpy.array([2]) > 1).any()
Perhaps you are confusing it with this
>>> (numpy.array([2]) > 1).any()
True