Nested if ... else (Python exercise) - python

I'm trying to build a function that checks which of a,b,c is less then returns the lesser value.
def minimal_three(a,b,c):
if a < b:
if a < c:
return (a)
elif b < a:
if b < c:
return (b)
elif c < a:
if c < b:
return (c)
else:
return 'none'
So far the code runs fine until it gets to check 'c', then it doesnt return anything, nested if else statements already get really confusing to me.

You shouldn't use if-else as the 3 conditions are not exclusive.
For example, [3, 4, 1] should return in the 3rd condition but is also suitable in the 1st condition, so it returns nothing.
If you don't want to change your code a lot. You can use:
def minimal_three(a,b,c):
if a < b:
if a < c:
return (a)
if b < a:
if b < c:
return (b)
if c < a:
if c < b:
return (c)
return 'none'
For simple, you can try:
def minimal_three(a,b,c):
return min(a, b, c)

why that code doesn't work:
def minimal_three(a,b,c):
if a < b:
if a < c:
return (a)
else:
# what if a >= c and a < b ?
return "i returned nothing"
elif b < a:
if b < c:
return (b)
else:
# what if b >= c and a > b ?
return "i returned nothing"
elif c < a:
if c < b:
return (c)
else:
# what if b <= c and a < c ?
return "i returned nothing"
else:
return 'none'
Alternative:
def min_of_two(a, b):
if a > b:
return b
return a
def min_of_three(a, b, c):
min_ab = min_of_two(a, b)
min_abc = min_of_two(min_ab, c)
return min_abc
def min_of_three_v2(a, b, c):
min_ab = a
if a > b:
min_ab = b
min_abc = min_ab
if min_ab > c:
min_abc = c
return min_abc
def min_of_three_v3(a, b, c):
min_abc = a
if min_abc > b:
min_abc = b
if min_abc > c:
min_abc = c
return min_abc
if you really want to use nested if/else (this code is so long):
# if-elif-else is ok.
# nested if is hard to read
# if-elif-elif-elif-elif...-else is hard to read.
# hard to read == easy to have bugs, which is bad.
def min_abc_slower(a, b, c):
if a > b:
# a > b. This means min(a, b) == b
if b > c:
# b > c. This means min(c, min(a, b)) == c
return c
else:
# b > c is False. This means b <= c.
# So, min(c, min(a, b)) == b
return b
else:
# a > b is False. This means a <= b.
# So, min(a, b) = a
if a > c:
# a > c. This means min(c, min(a, b)) == c
return c
else:
# a > c is False. This means a <= c
# So, min(c, min(a, b)) == a
return a

Use the power of if...elif...else over if...if...if or if...else...if...else. The way you have written your code, depreciates the power of elif. The correct way should be as this:
def minimal_three(a,b,c):
if a < b and a < c:
return (a)
elif b < c:
return (b)
else
return (c)
This code will always return the min no matter what numbers you give.
Explaination:
In your code, the line if a < b already tells you the comparison between a and b that which one is greater. So checking for this condition again in the second if if b < a is useless. if a is not lesser than b, then obviously it is either greater than b or equal to b. So now you must just check if b is lesser than c to prove that b is smallest or even a or b both but the returned value is always minimum. I hope you get that.
Also I don't understand whyt do you want to return None. If you provide three numbers to a function to find the minimum number, it should always and always return a number. Tell me a case where you can expect a None.

Easily be done using min inbuilt function:
def min_value(a,b,c):
return (min(a,min(b,c)))
also the number of steps in your code can be reduced with some tweaking.

It works - Finding two greatest in three int:
def Biggest(a, b, c):
if a >= b >= c:
print a, b, 'are the biggest two'
elif b >= c >= a:
print b, c, 'are the biggest two'
else:
print c, a, 'are the biggest two'
Find greatest in three integer:
def Biggest(a, y, z):
Max = a
if y > Max:
Max = y
if z > Max:
Max = z
if y > z:
Max = y
return Max

You could probably get away with using a for loop to minimise lines of code!
It would look something like this:
c = 3
b = 2
a = 1
list = [a,b,c]
def minimal_three(a,b,c):
for y in list:
n = y
for x in list:
if x < n:
print(n)

Related

Finding Inequality of 4 variables using Nested If else only

Lets say I have 4 variables, a,b,c and d.
I'm trying to write a code(in the shortest formate) using only If Else (in nested formate) to arrange the variables in accensending order.
I'm sure their possibly are ways to do it smothly but using this method do you think if the code can be shortened
Do you guys have any simpler way of finding inequality in such a way
**```
a=19
b=10
c=1
d=8
if a>b:
print()
if a>c:
print() #ALL OK
if a>d:
print()
if b>c:
print()
if c>d:
print("a>b>c>d")
else:
print("a>b>d>c")
else:
print()
if b>d:
print("a>c>b>d")
else:
print("a>c>d>b")
else:
print()
if b>c:
print("d>a>b>c")
else:
print("d>a>c>b")
else:
print()
if a>d:
print()
if d>b:
print("c>a>d>b")
else:
print("c>a>b>d")
else:
print()
if c>d:
print("c>d>a>b")
else:
print("d>c>a>b")
else:
print()
if b>c:
print()
if b>d:
print()
if a>c:
print()
if c>d:
print("b>a>c>d")
else:
print("b>a>d>c")
else:
print()
if a>d:
print("b>c>a>d")
else:
print("b>c>d>a")
else:
print()
if c>a:
print("d>b>c>a")
else:
print("d>b>a>c")
else:
print
if c>d:
print()
if a>d:
print("c>b>a>d")
else:
print("c>b>d>a")
else:
print("d>c>b>a")
```
`
```**
Probably don't want to use nested statements in this scope, as you can see it get's unweildly very quickly.
a = 19
b = 10
c = 1
d = 8
# Note you can shorten the nesting by using multi-conditional (might not be the term!)
if a > b > c > d: print("a>b>c>d")
elif b > c > d > a: print("b>c>d>a") # and so on..
# but you're still looking at hardcoding every possible permutation of [a, b, c,d] or in the event of a dataset with X elements..
# Nested if's are useful but not in this scope
# In the context of this problem it would be better to sort
# the data and create a string based on that
as_dict = {"a": a, "b": b, "c": c, "d": d}
sorted_d = sorted(as_dict, key=lambda x: as_dict[x])[::-1]
print(">".join(sorted_d))
#Pure pythonic You can try uisng and which will be clean & Append results to str order accordingly
a=19
b=10
c=1
d=8
s=''
how_many_var =4
for i in range(how_many_var):
if a > b and a > c and a > d:
print(a)
a=0
s += 'a>'
elif b > a and b > c and b > d:
print(b)
b=0
s += 'b>'
elif c > a and c > b and c > d:
print(c)
c=0
s += 'c>'
elif d > a and d > b and d > c:
print(d)
d=0
s += 'd'
print(s)
output #
19
10
8
1
a>b>d>c

Avoiding if else condition in python

I have two parameter, for example a,b. I have a situation like if both parameters(a,b) can have values or both may not have values or either of the one them have values.
Example:
1st Condition : a=10, b=20
2nd Condition: a=None, b=20
3rd Condition: a=10 , b=None
4th Condition: a=None, b= None
I have to do some operation if value is present and log it. Currently i am doing like below,
Is there any efficient way to do this?
if not a:
print "Value a not present"
if not b:
print "Value b not present"
# Do operation for A
a = a+1
# Do operation for B
b = b+1
You can collapse everything into two lines:
a = a + 1 if (a is not None) else (a or print('a not present'))
b = b + 1 if (b is not None) else (b or print('b not present'))
If a or b are None, the prints are executed. Here's a demo:
In [692]: a, b = 10, None
In [693]: a = a + 1 if (a is not None) else (a or print('a not present'))
...: b = b + 1 if (b is not None) else (b or print('b not present'))
...:
b not present
In [694]: a, b
Out[694]: (11, None)
At the end of the day, if you were to ask me what to use, I definitely wouldn't recommend the above. Compare this:
def check_and_increment(val):
if val is None:
return print('Not found!')
return val + 1
a = check_and_increment(a)
b = check_and_increment(b)
To my answer above. Which is more readable?
How about just using args instead, if the logic for all the params is going to be same?
def func(*args):
args = [value + 1 if value else value for value in args]
Otherwise, you can reduce the number of conditionals, but you have to use at least one.

If else condition with or, return variable that evaluates to FALSE

I was wondering about the most pythonic (and shortest) way to return the variable in an if else that evaluates to FALSE (or TRUE).
def foo(a,b)
if a == 0 or b == 0:
# return b
else:
pass;
a = 0
b = 1
print(foo(a,b))
> 1
Make use of the or operator short-circuiting:
def foo(a, b):
if a == 0 or b == 0:
return a or b
This returns b if a is 0. Note that if a and b are both 0, then 0 is returned.
If you really meant for these values to be booleans, then use the Python bool type values, False and True:
def foo(a, b):
if not (a and b): # equivalent of "not a or not b"
return a or b
foo(False, True) # produces True
foo(True, True) # produces None
Maybe I misunderstood the question, but isn't it the attempt to do this:
a = None
b = 123
c = a or b
print(c)
> 123
It is a pattern for initializing parameters for the functions with defaults if non-mandatory parameter was not set:
def func(a, b=None):
b = b or 'default_value'
print(a, b)
func('abc', 'b defined')
func('cde')

Python sum of non duplicate int

I am given 3 int, a, b, c. I would like to find the sum of all three int provided that they are unique. If a, b, or c has the same values as any of the other values, then they don't count towards the sum.
Example 1:
a = 3, b = 3, c =3
sum = 0
Example 2
a = 1, b = 3, c =3
sum = 1
This is what I have done. Is there a more pythonic way of doing this without so many if else statements?
def lone_sum(a, b, c):
if a != b and b != c and a != c:
return a + b + c
elif a == b == c:
return 0
elif a == b:
return c
elif b == c:
return a
elif a == c:
return b
from collections import Counter
def lone_sum(a, b, c):
d = Counter([a, b, c])
return sum(k for k in d if d[k]==1)
Add any number of numbers:
def lone_sum(*L):
d = Counter(L)
return sum(k for k in d if d[k]==1)
Add numbers repeated exactly c times:
def rep_sum(c, *L):
d = Counter(L)
return sum(k for k in d if d[k]==c)
Add numbers repeated at most c times:
def rep_sum(c, *L):
d = Counter(L)
return sum(k for k in d if d[k]<=c)
... or if you're bored and want to get really creative:
def lone_sum(*L):
nums = set()
all_nums = set()
for num in L:
if num in nums:
nums.remove(num)
elif num not in all_nums:
all_nums.add(num)
nums.add(num)
return sum(nums)
Here is a good beginners way to solve it
def lone_sum(*args):
return sum(x for x in args if args.count(x) == 1)
The issue with this is that args.count is a hidden loop, so the calculation becomes O(n2)
This doesn't matter much if there are only ever 3 arguments - ie n == 3.
A longhand way to write the same thing is
def lone_sum(a, b, c):
args = (a, b, c)
s = 0
for x in args:
if args.count(x) == 1:
s += x
return s
Here I take a list of your numbers, call it x, and then select only those x[i] which are not present in a list which is x without x[i]. That is, it removes all numbers which have a duplicate.
def lone_sum(a, b, c):
x = [a,b,c]
x = [x[i] for i in range(len(x)) if x[i] not in [x[j] for j in range(len(x)) if j!=i]]
return sum(x)
So,
[x[j] for j in range(len(x)) if j!=i]
is basically a list of elements excluding x[i]. It takes all elements apart from ith. If x[i] is in this list, it means it is a duplicate and we need to remove it. That is,
x[i] not in [x[j] for j in range(len(x)) if j!=i]
I think a lot has already been said and done on this topic and there is not much that can be added. But I too have written a program that uses sets to go about this task which is a little different from the top answer. So if you still wish to see all possible programs then here you go. Hope it helps!
def lone_sum(x):
c = set(x)
for b in c:
x.remove(b)
for a in set(x):
if a in c:
c.remove(a)
return(sum(c))

Looking for a more pythonic logical solution

I was doing some practice problems in Coding Bat, and came across this one..
Given 3 int values, a b c, return their sum. However, if one of the values is the same as another of the values, it does not count towards the sum.
lone_sum(1, 2, 3) → 6
lone_sum(3, 2, 3) → 2
lone_sum(3, 3, 3) → 0
My solution was the following.
def lone_sum(a, b, c):
sum = a+b+c
if a == b:
if a == c:
sum -= 3 * a
else:
sum -= 2 * a
elif b == c:
sum -= 2 * b
elif a == c:
sum -= 2 * a
return sum
Is there a more pythonic way of doing this?
Another possibility that works for an arbitrary number of arguments:
from collections import Counter
def lone_sum(*args):
return sum(x for x, c in Counter(args).items() if c == 1)
Note that in Python 2, you should use iteritems to avoid building a temporary list.
How about:
def lone_sum(*args):
return sum(v for v in args if args.count(v) == 1)
A more general solution for any number of arguments is
def lone_sum(*args):
seen = set()
summands = set()
for x in args:
if x not in seen:
summands.add(x)
seen.add(x)
else:
summands.discard(x)
return sum(summands)
Could use a defaultdict to screen out any elements appearing more than once.
from collections import defaultdict
def lone_sum(*args):
d = defaultdict(int)
for x in args:
d[x] += 1
return sum( val for val, apps in d.iteritems() if apps == 1 )
def lone_sum(a, b, c):
z = (a,b,c)
x = []
for item in z:
if z.count(item)==1:
x.append(item)
return sum(x)
Had a very similar approach to what you had:
def lone_sum(a, b, c):
if a != b and b != c and c != a:
return a + b + c
elif a == b == c:
return 0
elif a == b:
return c
elif b == c:
return a
elif c == a:
return b
Since if 2 values are the same the code will automatically return the
remaining value.
I tried this on Codingbat but it doesn`t work, although it does on the code editor.
def lone_sum(a, b, c):
s = set([a,b,c])
return sum(s)

Categories