Python IF statement to a single line - python

Is it possible to put this code into a single line?
if x == 0:
a += j["sum"]
elif x == 1:
b += j["sum"]
e.e. :D
This is not a working example just for demonstration purposes
a += j["sum"] if x == 0 else b += j["sum"]

You can do it this way if you have Python 3.8 or later for the assignment expression operator :=:
(a := a + j["sum"]) if x == 0 else (b := b + j["sum"]) if x == 1 else None
but really the original is best. It's preferable that code is clear and straightforward.

I may suggest you this one-line dual assignment:
a, b = a + (j["sum"] if x == 0 else 0), b + (j["sum"] if x == 1 else 0)
But you can also use the old good semi-colon to perform two instructions on one line:
a += (j["sum"] if x == 0 else 0); b += (j["sum"] if x == 1 else 0)

I would strongly discourage it, but I guess one could use boolean true as the multiplication identity to do:
a, b = a + (x==0) * j["sum"], b + (x==1) * j["sum"]
This seems to work as I expect in a little loop
a=100
b=200
jsum=10
for x in range(3):
a, b = a + (x==0) * jsum, b + (x==1) * jsum
print(a, b)
Giving:
110 200
110 210
110 210

While I would not code like this myself, one might throw caution to the wind and leverage exec():
exec(f"{['a','b'][x]} += j['sum']" if x in [0,1] else "pass")
or potentially even better (credit to #wjandrea):
if x in {0, 1}: exec(f"{['a','b'][x]} += j['sum']")
Note, if you know x is always either 0 or 1 this would simplify to:
exec(f"{['a','b'][x]} += j['sum']")
Your pseudo-code solution suggests that might be so but your questions suggests it is not.
example:
a=100
b=200
jsum=10
for x in range(3):
exec(f"{['a','b'][x]} += jsum" if x in [0,1] else "pass")
print(a, b)
giving:
110 200
110 210
110 210
#wjandrea has suggested a nice improvement that produces the same results and is likely faster given the ability to bypass exec() if x is out of range.
a=100
b=200
jsum=10
for x in range(3):
if x in {0, 1}: exec(f"{['a','b'][x]} += jsum")
print(a, b)

Related

Clear mathematical way to cast int value to 0 or 1

Maybe it's too trivial question but I can't find answer if there is a some more elegant way to cast int value to 0 or 1 without using condition or type casting?
Now I have only following variants and both are ugly:
x = 5
a = some_int_value * (1 if x > 0 else 0)
b = some_int_value * int(bool(x))
ADDED
x is a non-negative value.
To paraphrase your condition, x can be 0 or a value larger than 0. If x > 0, you want to use the value some_int_value, otherwise you want 0 (which is identical to x). Then do:
c = x and some_int_value
If x is 0, i.e. falsey, the and expression returns x. If x is truthy (non-zero), it returns some_int_value.
Arguably even more comprehensible would be:
d = some_int_value if x > 0 else 0
Or:
e = 0
if x > 0:
e = some_int_value
Another way without functions, casting, or conditionals, but with comparisons:
d = some_int_value * (x > 0)
However, in terms of readability, a ternary ... if ... else ... should probably be preferred.
If you want a purely mathematical way, you can use exponentiation with 1 - 0x, since 0**x is 1 only if x == 0 and 0 otherwise. But whether that is in any way clear is another question. (Also note that this gives a division-by-zero for x < 0, but you said that you don't have those.)
>>> x = 5
>>> 1 - 0**x
1
>>> x = 0
>>> 1 - 0**x
0

How does Big O notation work?

Ok so I'm fairly new to coding and I am to approximate a WCET T(a, b) and complexity of a function. Example function:
def testFunction(self):
x = 0
for r in range(a):
for c in range(b):
if testFunction2(r, c):
x = x + 1
return x
I understand that the complexity of this function is quadratic O(N^2) but I'm not sure on approximating the WCET?
Also isn't there only two assignments in that function, being:
x = 0
and
x = x + 1
?
If so, how do I express the assignments with T(a, b)?
Maths has never been my strong point but I want to learn how to do this. None of the materials I've read explains it in a way I understand.
Thanks in advance.
def testFunction(self):
x = 0 # 1
for r in range(a): # a
for c in range(b): # b
if testFunction2(r, c): # a*b
x = x + 1 # depends testFunction2
return x # 1
WCET for this function ab where a=n b=n then you can say O(n^2)
if always testFunction2 returns True then x = x +1 will execute ab times but it wont effect the sum of execution time.
Finally you sum all this exection time:
(1 + a + b + a*b + a*b + 1)
2 + a + b + 2*a*b
for example, while n = 1000 and a=b=n
2 + 1000 + 1000 + 2*1000*1000
2002 + 2000000
so when you evalute this result you will see 2002 is nothing while you have 2000000.
For a Worst Case Execution Time, you can simply assume there is an input specifically crafted to make your program slow. In this case that would be testfunction2 always returns true.
Within the body of the loop, the assignment x = x + 1 happens a * b times in the worst case.
Instead of describing this as O(N^2), I would describe it as O(ab), and then note for a ~= b ~= N that is O(N^2)

Python - nesting if else inside return

Can an if-else expression be the argument of 'return'?
Here's an example of what I'm trying to do:
return m +
if a:
x
elif b:
y
else c:
z
I could write as:
addend = m
if a:
m += x
elif b:
m += y
else c:
m += z
return m
Well, you can use Python's ternary method, such as:
return m + (x if a else y if b else z)
But it may be more readable to just do something like:
if a: return m + x
if b: return m + y
return m + z
As an aside, else c: is not really sensible code: you use if/elif if you have a condition, or else for default action (no condition).
For example, in terms of the code you posted in a comment, you could opt for the succinct, yet still self-documenting:
def rental_car_costs(days):
basecost = days * 40
discount = 50 if days >= 7 else 20 if days >= 3 else 0
return basecost - discount

Sum of even integers from a to b in Python

This is my code:
def sum_even(a, b):
count = 0
for i in range(a, b, 1):
if(i % 2 == 0):
count += [i]
return count
An example I put was print(sum_even(3,7)) and the output is 0. I cannot figure out what is wrong.
Your indentation is off, it should be:
def sum_even(a, b):
count = 0
for i in range(a, b, 1):
if(i % 2 == 0):
count += i
return count
so that return count doesn't get scoped to your for loop (in which case it would return on the 1st iteration, causing it to return 0)
(And change [i] to i)
NOTE: another problem - you should be careful about using range:
>>> range(3,7)
[3, 4, 5, 6]
so if you were to do calls to:
sum_even(3,7)
sum_even(3,8)
right now, they would both output 10, which is incorrect for sum of even integers between 3 and 8, inclusive.
What you really want is probably this instead:
def sum_even(a, b):
return sum(i for i in range(a, b + 1) if i % 2 == 0)
Move the return statement out of the scope of the for loop (otherwise you will return on the first loop iteration).
Change count += [i] to count += i.
Also (not sure if you knew this), range(a, b, 1) will contain all the numbers from a to b - 1 (not b). Moreover, you don't need the 1 argument: range(a,b) will have the same effect. So to contain all the numbers from a to b you should use range(a, b+1).
Probably the quickest way to add all the even numbers from a to b is
sum(i for i in xrange(a, b + 1) if not i % 2)
You can make it far simpler than that, by properly using the step argument to the range function.
def sum_even(a, b):
return sum(range(a + a%2, b + 1, 2))
You don't need the loop; you can use simple algebra:
def sum_even(a, b):
if (a % 2 == 1):
a += 1
if (b % 2 == 1):
b -= 1
return a * (0.5 - 0.25 * a) + b * (0.25 * b + 0.5)
Edit:
As NPE pointed out, my original solution above uses floating-point maths. I wasn't too concerned, since the overhead of floating-point maths is negligible compared with the removal of the looping (e.g. if calling sum_even(10, 10000)). Furthermore, the calculations use (negative) powers of two, so shouldn't be subject by rounding errors.
Anyhow, with the simple trick of multiplying everything by 4 and then dividing again at the end we can use integers throughout, which is preferable.
def sum_even(a, b):
if (a % 2 == 1):
a += 1
if (b % 2 == 1):
b -= 1
return (a * (2 - a) + b * (2 + b)) // 4
I'd like you see how your loops work if b is close to 2^32 ;-)
As Matthew said there is no loop needed but he does not explain why.
The problem is just simple arithmetic sequence wiki. Sum of all items in such sequence is:
(a+b)
Sn = ------- * n
2
where 'a' is a first item, 'b' is last and 'n' is number if items.
If we make 'a' and b' even numbers we can easily solve given problem.
So making 'a' and 'b' even is just:
if ((a & 1)==1):
a = a + 1
if ((b & 1)==1):
b = b - 1
Now think how many items do we have between two even numbers - it is:
b-a
n = --- + 1
2
Put it into equation and you get:
a+b b-a
Sn = ----- * ( ------ + 1)
2 2
so your code looks like:
def sum_even(a,b):
if ((a & 1)==1):
a = a + 1
if ((b & 1)==1):
b = b - 1
return ((a+b)/2) * (1+((b-a)/2))
Of course you may add some code to prevent a be equal or bigger than b etc.
Indentation matters in Python. The code you write returns after the first item processed.
This might be a simple way of doing it using the range function.
the third number in range is a step number, i.e, 0, 2, 4, 6...100
sum = 0
for even_number in range(0,102,2):
sum += even_number
print (sum)
def sum_even(a,b):
count = 0
for i in range(a, b):
if(i % 2 == 0):
count += i
return count
Two mistakes here :
add i instead of [i]
you return the value directly at the first iteration. Move the return count out of the for loop
The sum of all the even numbers between the start and end number (inclusive).
def addEvenNumbers(start,end):
total = 0
if end%2==0:
for x in range(start,end):
if x%2==0:
total+=x
return total+end
else:
for x in range(start,end):
if x%2==0:
total+=x
return total
print addEvenNumbers(4,12)
little bit more fancy with advanced python feature.
def sum(a,b):
return a + b
def evensum(a,b):
a = reduce(sum,[x for x in range(a,b) if x %2 ==0])
return a
SUM of even numbers including min and max numbers:
def sum_evens(minimum, maximum):
sum=0
for i in range(minimum, maximum+1):
if i%2==0:
sum = sum +i
i= i+1
return sum
print(sum_evens(2, 6))
OUTPUT is : 12
sum_evens(2, 6) -> 12 (2 + 4 + 6 = 12)
List based approach,
Use b+1 if you want to include last value.
def sum_even(a, b):
even = [x for x in range (a, b) if x%2 ==0 ]
return sum(even)
print(sum_even(3,6))
4
[Program finished]
This will add up all your even values between 1 and 10 and output the answer which is stored in the variable x
x = 0
for i in range (1,10):
if i %2 == 0:
x = x+1
print(x)

Solving three variables Diophantine equation in Python

I'm a beginner in Python, and tried to take MIT 6.00, the page provided is the assignments page.
I'm at assignment 2, where i have to find a solution for Diophantine equation, i'm really not that great in math, so i tried to understand what it does as much as i can, and think of a solution for it.
Here's what i got to :
def test(x):
for a in range(1,150):
for b in range(1,150):
for c in range(1,150):
y = 6*a+9*b+20*c
if y == x:
print "this --> " , a, b, c
break
else : ##this to see how close i was to the number
if y - x < 3:
print a, b, c , y
The assignment states that there's a solution for 50, 51, 52, 53, 54, and 55, but unfortunately the script only gets the solution for 50, 53 and 55.
I'd be very grateful if someone explained what's wrong in my code, or if i'm not understanding Diophantine equation at all, please tell me what is it all about and how to find a solution for it, since i cant get the assignment's explanation into my head.
Thanks.
The assignment says:
To determine if it is possible to
buy exactly n McNuggets, one has to solve a Diophantine equation: find non-negative integer
values of a, b, and c, such that
6a + 9b + 20c = n.
It seems that you have to include zero in the ranges of your function. That way, you can find solutions for all the numbers you need.
A solution to
6*a+9*b+20*c = 51
with integers a, b, c must have at least one of the integers 0 or negative. Some solutions are
6*7 + 9*1 + 20*0 = 51
6*0 + 9*(-1) + 20*3 = 51
Depending on the constraints in the assignment, you need to include 0 or even negative numbers among the possible coefficients.
A solution for 51 is 5*9 + 1*6.
Hint: where's the 20? What does this mean for it's coefficient?
A solution for 54 is 3*20 + (-1)*6. You figure out the rest.
For a start, you can usefully exploit bounds analysis. Given
6a + 9b + 20c = n
0 <= a
0 <= b
0 <= c
we can systematically set pairs of {a, b, c} to 0 to infer the upper bound for the remaining variable. This gives us
a <= floor(n / 6)
b <= floor(n / 9)
c <= floor(n / 20)
Moreover, if you pick a strategy (e.g., assign c then b then a), you can tighten the upper bounds further, for instance:
b <= floor((n - 20c) / 9)
Also, the last variable to be assigned must be a function of the other variables: you don't need to search for that.
You can start your range for a,b,c from 0 to 150.
Actually even I am a beginner and have started out from MIt 6.00 only.
ON reading their problem ,I think 150 it the limit to the largest number which cannot be possible to take.
This is a solution in Perl. rather a hack by using Regex.
Following this blog post to solve algebraic equations using regex.
we can use the following script for 3x + 2y + 5z = 40
#!/usr/bin/perl
$_ = 'o' x 40;
$a = 'o' x 3;
$b = 'o' x 2;
$c = 'o' x 5;
$_ =~ /^((?:$a)+)((?:$b)+)((?:$c)+)$/;
print "x = ", length($1)/length($a), "\n";
print "y = ", length($2)/length($b), "\n";
print "z = ", length($3)/length($c), "\n";
output: x=11, y = 1, z = 1
the famous Oldest plays the piano puzzle ends up as a 3 variable equation
This method applies for a condition that the variables are actually positive and the constant is positive.
Check this one I adapted from yours. It seems to fixed your problem:
variables=range(0,10)
exams=range(51,56)
for total in exams:
for a in variables:
for b in variables:
for c in variables:
if total==4*a+6*b+20*c:
print a, 'four pieces', b, 'six pieces','and', c ,'twenty pieces', 'for a total of', total
The break function will only break out of the closest loop. The code below uses an indicator to break out of each loop.
n = 1 # n starting from 1
count = 0 # Count + 1 everytime we find a possible value.
# Reset = 0 after a non-possible value.
notPossibleValue = ()
while True:
ind = 0 # become 1 if int solutions were found
for c in range (0,n/20+1):
if ind == 1: break
for b in range (0,n/9+1):
if ind == 1: break
for a in range (0, n/6+1):
if (n-20*c) == (b*9+a*6):
count += 1
ind = 1
# print 'n=', n, a,b,c, 'count', count
break # Break out of "a" loop
if ind == 0:
count = 0
notPossibleValue += (n,)
# print notPossibleValue, 'count', count
if count == 6:
print 'The largest number of McNuggets that cannot be bought in exact quantity is', notPossibleValue[-1]
break
n += 1
n=1
a=0
b=0
c=0
mcnugget = []
for i in range (n,100):
for a in range (0,20):
if 6*a + 9* b +20*c ==i:
mcnugget.append(i)
break
else:
for b in range (0,12):
if 6*a + 9* b +20*c ==i:
mcnugget.append(i)
break
else:
for c in range(0,5):
if 6*a + 9* b +20*c ==i:
mcnugget.append(i)
break
else:
if i>8:
if mcnugget[-1]==mcnugget[-2]+1==mcnugget[-3]+2==mcnugget[-4]+3==mcnugget[-5]+4==mcnugget[-6]+5 and mcnugget[-6]>0 :
break
mcnugget = set (mcnugget)
mcnugget = list (mcnugget)
count = 0
for z in mcnugget:
count += 1
if mcnugget [count]==mcnugget [count-1]+1==mcnugget [count-2]+2==mcnugget [count-3]+3==mcnugget [count-4]+4==mcnugget[count-5]+5:
biggestN= mcnugget[count-6]
break
#print (mcnugget)
biggestN = str(biggestN)
print ('Largest number of McNuggets that cannot be bought in exact quantity: <'+ biggestN +'>')

Categories