IF statement with 2 variables and 4 conditions - python

I have 2 variables, say x and y, and I need to check which of them is None
if x is None and y is None:
# code here
else:
if x is not None and y is not None:
# code here
else:
if x is None:
# code here
if y is None:
# code here
Is there a better approach to do this?
I am looking for a shorter IF ELSE structure.

Keeping the order you used:
if x is None and y is None:
# code here for x = None = y
elif x is not None and y is not None:
# code here for x != None != y
elif x is None:
# code here for x = None != y
else:
# code here for x != None = y
Modifying the order to reduce boolean evaluations:
if x is None and y is None:
# code here for x = None = y
elif x is None:
# code here for x = None != y
elif y is None:
# code here for x != None = y
else:
# code here for x != None != y
In a 4 case scenario, you should consider which of the options has a higher probability and which has the second higher and keep them the first two options, as this will reduce the amount of conditions checked during execution. The last two options will both execute the 3 conditions so the order of these two doesn't matter. For example the first code above considers that prob(x=None & y=None) > prob(x!=None & y!=None) > prob(x=None & y!=None) ~ prob(x!=None & y=None) while the second one considers that prob(x=None & y=None) > prob(x=None & y!=None) > prob(x!=None & y=None) ~ prob(x!=None & y!=None)

def func1(a):
print a
def func2(a):
print a
def func3(a):
print a
def func4(a):
print a
options = {(1, 1): func1,
(1, 0): func2,
(0, 1): func3,
(0, 0): func4,}
options[(True, True)](100)
output:
100

If you need 4 different paths for each of the possible combination of x and y, you can't really simplify it that much. That said, I would group the checks for one of the variables (i.e. check if x is None first, then inside, check if y is None.)
Something like this:
if x is None:
if y is None:
# x is None, y is None
else:
# x is None, y is not None
else:
if y is None:
# x is not None, y is None
else:
# x is not None, y is not None

you can start by using the elif statement, it will be a little bit shorter just like this:
if x is None and y is None:
# code here
elif x is not None and y is not None:
# code here
elif x is None:
# code here
if y is None:
# code here`

Assuming you need to have all 4 cases covered seperately:
if not x and not y:
# code here (both are none or 0)
elif not x
# code here (x is none or 0)
elif not y
# code here (y is none or 0)
else
#code here (both x and y have values)
This would be the shortest way to handle it, but doesn't only check for None/Null values. not x returns true for anything falsey, such as empty strings, False, or 0.

If you have two booleans, there are four distinct possibilities: 00 01 10 and 11. If in each case something distinctly different is supposed to happen, there is not really something that could reduce the number of tests.
Having said that, in some comparable cases pattern matching might feel more straightforward. I don't know about that in Python though.

The below logic should run for all the combination. Write in your language
if (x is not null and y is not null){
//code here
}
else if(x is null and y is not null){
//code here
}
else if(x is not null and y is null){
//code here
}
else
{
//Code here
}
The C Code for the same:
int main()
{
int x,y;
printf("Enetr Two Number");
scanf("%d%d",&x,&y);
if(x!=NULL && y!=NULL)
printf("X and Y are not null");
else if(x==NULL && y!=NULL)
printf("X is null and Y is not null");
else if(x!=NULL && y==NULL)
printf("X is not null and Y is null");
else
{
printf("The value of x and y are null");
}
}

Related

Check if multiple variables have the same value

I have a set of three variables x, y, z and I want to check if they all share the same value. In my case, the value will either be 1 or 0, but I only need to know if they are all the same. Currently I'm using
if 1 == x and 1 == y and 1 == z:
sameness = True
Looking for the answer I've found:
if 1 in {x, y, z}:
However, this operates as
if 1 == x or 1 == y or 1 == z:
atleastOneMatch = True
Is it possible to check if 1 is in each: x, y, and z?
Better yet, is there a more concise way of checking simply if x, y, and z are the same value?
(If it matters, I use Python 3.)
If you have an arbitrary sequence, use the all() function with a generator expression:
values = [x, y, z] # can contain any number of values
if all(v == 1 for v in values):
otherwise, just use == on all three variables:
if x == y == z == 1:
If you only needed to know if they are all the same value (regardless of what value that is), use:
if all(v == values[0] for v in values):
or
if x == y == z:
To check if they are all the same (either 1 or 2):
sameness = (x == y == z)
The parentheses are optional, but I find it improves readability
How about this?
x == y == z == 1
In my case, the value will either by 1 or 2, but I only need to know if they are all the same
Is it possible to check if 1 is in each: x, y, and z?
Better yet, is there a more concise way of checking simply if x, y, and z are the same value?
Sure:
x == y == z
which is equivalent to
(x == y) and (y == z)
If you have an arbitrary (nonzero) number of values to compare:
all(values[0] == v for v in values[1:])
You could use something similar to what you have:
sameness = (len({x, y, z}) == 1)
This allows for any number of variables. For example:
variables = {x, y, z, a, b, ...}
sameness = (len(variables) == 1)
Note: Creating a set means that each variable needs to be hashed and the hashed values need to be stored, but all() with a generator expression is short-circuiting and keeps track of only two values at a time. Therefore, besides its readability, the generator expression is more efficient.
Another way:
sameness = all(e == 1 for e in [x, y, z])
[x,y,z].count(1)
will count how many variables have 1 as value
Below all() and any() functions in python can server the purpose.
all() act as "AND": if all the values in any ittertable object is equal to given condition value, then Return True else return False.
Examples
assert all(b == True for b in [True,True,True,True]) == True
assert all(b == True for b in [False,True,True,True]) == False
any() act as "OR": if any one value in any ittertable object is equal to given condition value, then Return True else return False.
Examples
assert any(b == True for b in [False,False,False,True]) == True
assert any(b == True for b in [False,False,False,False]) == False
If you had more variables, this way might be most concise:
{x} == {y, z}
(Not as fast as x == y == z, but the question asked for concise, not for fast.)

How to stop a loop?

def sum_div(x, y):
for k in range(x,y+1):
for z in range(x,y+1):
sx = 0
sy = 0
for i in range(1, k+1):
if k % i == 0:
sx += i
for j in range(1, z+1):
if z % j == 0:
sy += j
if sx == sy and k!= z:
print "(", k ,",", z, ")"
x = input("Dati x : ")
y = input("Dati y : ")
sum_div(x, y)
How do I stop the looping if the value of z == y?
The loops print a pair of numbers in a range from x to y, but when it hit the y value the loop prints a reverse pair of numbers that I don't need it to.
The break command will break out of the loop. So a line like this:
if (z == y):
break
should do what you want.
What you're think you are asking for is the break command, but what you're actually looking for is removal of duplication.
Your program lacks some clarity. For instance:
for i in range(1, k+1):
if k % i == 0:
sx += i
for j in range(1, z+1):
if z % j == 0:
sy += j
These two things are doing essentially the same thing, which can be written more cleanly with a list comprehension (in the REPL):
>>> def get_divisors(r: int) -> list:
... return [i if r % i == 0 else 0 for i in range(1, r+1)]
...
...
>>> get_divisors(4)
>>> [1, 2, 0, 4]
>>> sum(get_divisors(4))
>>> 7
Your line:
while y:
... will infinitely loop if you find a match. You should just remove it. while y means "while y is true", and any value there will evaluate as true.
This reduces your program to the following:
def get_divisors(r: int) -> list:
return [i if r % i == 0 else 0 for i in range(1, r+1)]
def sum_div(x, y):
for k in range(x,y+1):
sum_of_x_divisors = sum(get_divisors(k)) # Note this is moved here to avoid repeating work.
for z in range(x,y+1):
sum_of_y_divisors = sum(get_divisors(z))
if sum_of_x_divisors == sum_of_y_divisors and k!= z:
print("({},{})".format(k, z))
Testing this in the REPL it seems correct based on the logic of the code:
>>> sum_div(9,15)
(14,15)
(15,14)
>>> sum_div(21, 35)
(21,31)
(31,21)
(33,35)
(35,33)
But it's possible that for sum_div(9,15) you want only one of (14,15) and (15,14). However, this has nothing to do with breaking your loop, but the fact that what you're attempting to do has two valid values when k and z don't equal each other. This is demonstrated by the second test case, where (33,35) is a repeated value, but if you broke the for loop on (21,31) you would not get that second set of values.
One way we can account for this is by reordering when work is done:
def sum_div(x, y):
result_set = set() # Sets cannot have duplicate values
for k in range(x,y+1):
sum_of_x_divisors = sum(get_divisors(k))
for z in range(x,y+1):
sum_of_y_divisors = sum(get_divisors(z))
if sum_of_x_divisors == sum_of_y_divisors and k!= z:
result_set.add(tuple(sorted((k,z)))) # compile the result set by sorting it and casting to a tuple, so duplicates are implicitly removed.
for k, z in result_set: # Print result set after it's been compiled
print("({},{})".format(k, z))
And we see a correct result:
>>> sum_div(9,15)
(14,15)
>>> sum_div(21,35)
(21,31)
(33,35)
Or, the test case you provided in comments. Note the lack of duplicates:
>>> sum_div(10,25)
(16,25)
(14,15)
(15,23)
(10,17)
(14,23)
Some takeaways:
Break out functions that are doing the same thing so you can reason more easily about it.
Name your variables in a human-readable format so that we, the readers of your code (which includes you) understands what is going on.
Don't use loops unless you're actually looping over something. for, while, etc. only need to be used if you're planning on going over a list of things.
When asking questions, be sure to always include test input, expected output and what you're actually getting back.
The current best-practice for printing strings is to use the .format() function, to make it really clear what you're printing.

sum variable in a range (python)

This was the question:
Write a function called sum_range that accepts 2 integer values as
parameters and returns the sum of all the integers between the two
values, including the first and last values. The parameters may be in
any order (i.e. the second parameter may be smaller than the first).
For example:
result = sum_range(1, 1)
print(result) 1
result = sum_range(2, 4) print(result) 9
result = sum_range(3, 2)
print(result) 5
my codes are as below, I dont know where it went wrong
but when I test the codes, it returned 'none' when (2,4) (3,2) were entered
def sum_range(x,y):
if x == y:
return x
if x<y:
sum(range(x,y))
return
if x>y:
sum(range(y,x))
return
You could do better (at least I think), here is my code for that:
def sum_range(a, b):
return sum(range(min(a,b),max(a,b)+1))
You were very close but forgot to return the actual value from the calculations. If you just type "return", you will return None and not the result from the sum.
You also did not include the last number in the range in the sum. See corrected code below:
def sum_range(x, y):
if x == y:
return x
if x < y:
return sum(range(x, y+1))
if x > y:
return sum(range(y, x+1))
You need to return the sum which you are not doing in the x<y and x>y cases. You should
return sum(range(x,y)) or return sum(range(y,x)) as appropriate.
Note also that there is a bug in your range() expressions - "including the first and last values". Hint: What does range(1,3) output?
def sum_range(x,y):
if x == y:
return x
elif x < y:
s = 0
for i in range(x,y):
s += x+(x+1)
return s
elif x > y:
s = 0
for i in range(y,x):
s += y+(y+1)
return s
This is done without using sum() function.

Usage of the "==" operator for three objects

Is there any computational difference between these two methods of checking equality between three objects?
I have two variables: x and y. Say I do this:
>>> x = 5
>>> y = 5
>>> x == y == 5
True
Is that different from:
>>> x = 5
>>> y = 5
>>> x == y and x == 5
True
What about if they are False?
>>> x = 5
>>> y = 5
>>> x == y == 4
False
And:
>>> x = 5
>>> y = 5
>>> x == y and x == 4
False
Is there any difference in how they are calculated?
In addition, how does x == y == z work?
Thanks in advance!
Python has chained comparisons, so these two forms are equivalent:
x == y == z
x == y and y == z
except that in the first, y is only evaluated once.
This means you can also write:
0 < x < 10
10 >= z >= 2
etc. You can also write confusing things like:
a < b == c is d # Don't do this
Beginners sometimes get tripped up on this:
a < 100 is True # Definitely don't do this!
which will always be false since it is the same as:
a < 100 and 100 is True # Now we see the violence inherent in the system!
Adding a little visual demonstration to already accepted answer.
For testing equality of three values or variables. We can either use:
>>> print(1) == print(2) == print(3)
1
2
3
True
>>> print(1) == print(2) and print(2) == print(3)
1
2
2
3
True
The above statements are equivalent but not equal to, since accesses are only performed once. Python chains relational operators naturally. See this docs:
Comparisons can be chained arbitrarily, e.g., x < y <= z is equivalent to x < y and y <= z, except that y is evaluated only once (but in both cases z is not evaluated at all when x < y is found to be false).
If the functions called (and you are comparing return values) have no side-effects, then the two ways are same.
In both examples, the second comparison will not be evaluated if the first one evaluates to false. However: beware of adding parentheses. For example:
>>> 1 == 2 == 0
False
>>> (1 == 2) == 0
True
See this answer.

Python Version of Perl = || (= Or)

I can't seem to find a python way of saying
x = y or 1
In Perl:
$x = $y || 1;
Is there a nice way to do this in python?
Python's or has what I believe are the semantics you're looking for. See the documentation. It's important to realize that it returns the input value(s), not True or False.
>>> "" or 12
12
>>> 27 or 9
27
>> None or "default"
'default'
This should mean that x = y or 1 should be what you're after, x will be y if y is non-False, else it will be 1.
x = y or 1 is the same as:
if y:
x = y
else:
x = 1
Isn't it what you're trying to do?
y = 2
x = y if y else 1
# x == 2
y = None
x = y if y else 1
# x == 1
All the solutions mentioned will work if y is defined (it can be None)
If y is not defined Python will throw an exception, while the Perl code will work in non-strict mode.
A simple one but not that nice:
x = y if y else 1

Categories

Resources