I'm new to programming and this is my first time asking a question, so apologies in advance if I'm breaking any protocols. I tried searching for an answer before posting, but I didn't find any matching results.
I'm working my way through Think Python 2, and here is my solution to exercise 5.3, the triangle exercise.
def is_tri():
print('Give me 3 lengths')
a = int(input('first?\n'))
b = int(input('second?\n'))
c = int(input('third?\n'))
if a > b + c or b > a + c or c > a + b:
print('Not a triangle')
else:
print("Yes, it's a triangle")
is_tri()
What I noticed is that if I give 3 answers wherein 2 of the lengths equal the third when added together, i.e. (1,1,2), the program returns Yes. But 2 is not greater than 2. I even added a series of 'and' statements requiring that the sum of any two sides must not equal the third, and it still returns Yes:
if (a > b + c or b > a + c or c > a + b) and (a != b + c and b != a + c and c != a + b):
The author mentions that the sum of two sides equaling the third is a 'degenerate triangle', perhaps anticipating this outcome. But why? Don't the '>' and '>=' operators provide different functions? Am I missing something? How can I constrain the operator to exclude degenerate triangles?
If you need to declare that triangles that have the largest side equal to the sum of the others are invalid you are using the wrong operator, you should use == in conjunction to >, so your condition would look like:
if (a > b + c or a == b + c) or (b > a + c or b == a + c ) or (c > a + b or c == a + b):
Which is exactly the same as to making it like this:
if a >= b + c or b >= a + c or c >= a + b:
One nice way of doing it is sorting the list to get the largest element and then comparing to the sum of the others using slices, for this you would need the inputs to be in a list:
triangle_sides = [int(input('first?\n')), int(input('second?\n')), int(input('third?\n'))]
triangle_sides = sorted(triangle_sides, reverse=True)
if triangle_sides[0] >= sum(triangle_sides[1:]):
print("Absolutelly not a triangle")
else:
print("Congratulations, its a triangle")
I would also recommend you to get your inputs from outside the function, separating the "user interface" from the logic, your script would look like:
def is_valid_triangle(triangle_sides):
triangle_sides = sorted(triangle_sides, reverse=True)
if triangle_sides[0] >= sum(triangle_sides[1:]):
return False
return True
def triangle_validator():
print('Give me 3 lengths')
triangle_sides = [
int(input('first?\n')),
int(input('second?\n')),
int(input('third?\n'))
]
if is_valid_triangle(triangle_sides):
print('Yes, it\'s a triangle')
else:
print('Not a triangle')
if __name__ == '__main__':
triangle_validator()
Your condition clearly states that the line lengths do not form a triangle only if one length is strictly greater than the sum of the other two. That's not the condition you're looking for. You want to disqualify the input if one is greater or equal to the sum of the other two.
This would work:
if a >= b + c or b >= a + c or c >= a + b:
Related
So, I was writing overly complex answers for simple problems on Codewars as I often do, and one of the problems was,
Multiply two numbers
It wanted me to put:
return a * b
But I wanted to make a function that multiplied two numbers by itself, without the help of the '*' operator or any other thing that multiplied values together.
Pretty easy, I thought. I just add the a value to some empty value b amount of times.
It worked pretty well, up until one of the tests included decimals. I then wrote this to get the average of.. well something. That clearly didn't work:
def multiply(a, b):
leftside = 0
rightside = 0
average = 0
for i in range(int(b)):
leftside += a
for i in range(int(a)):
rightside += b
average = (leftside+rightside) / 2
return average
So basically, what I'm asking is if there's a way to naturally, without any other functions or operators(besides addition and essential things) to multiply values.
If you allow division by 2 like your own attempt does, then I guess this might be decent:
def multiply(a, b):
while b >= 1:
b /= 2
a += a
result = 0
while b:
b += b
a /= 2
if b >= 1:
result += a
b -= 1
return result
Or implementing halving myself, without using division:
def half(x):
result = 0
while x:
y = 0
Y = 2.2250738585072014e-308
while Y + Y <= x:
y = Y
Y += Y
x -= Y
result += y
return result
def multiply(a, b):
while b >= 1:
b = half(b)
a += a
result = 0
while b:
b += b
a = half(a)
if b >= 1:
result += a
b -= 1
return result
This is the code about to find out dice gamble's prize amount:
a, b, c = map(int, input().split())
if a == b and b == c: #same all of dice numbers
print(10000 + (a * 1000))
elif a == b or b == c: #same two of dice numbers
print(1000 + (b * 100))
elif a == c: #same two of dice numbers
print(1000 + (a * 100))
else: #no same number
print(max(a, b, c)*100)
This is equivalent:
*_, a, b, c=sorted(input())
print(['1'+b, c][a < b < c]+'000'[a < c:])
But i can't understanding about what does
['1'+b, c][a < b < c]
and
'000'[a < c:]
do.
So, I had tried to find out the meaning of
`['1'+b, c][a < b < c]`
I found this is similar with
`c if a<b<c else '1'+b`
but i can't be sure about that.
anyway, about
`'000'[a < c:]`
I tried input a=c to
`print('000'[a < c:])`
It shows 000.
I tried else that input a<c, it shows 00
Anyone can tell me about this expression?
The original is unnecessarily cryptic. It uses the fact that:
int(False) == 0
int(True) == 1
For instance,
'000'[False:] == '000'[0:] == '000'
'000'[True:] == '000'[1:] == '00'
Similarly,
['1' + b, c][False] == ['1' + b, c][0] == '1' + b
['1' + b, c][True] == ['1' + b, c][1] == c
Here's an equivalent rewrite:
prefix = c if a < b < c else '1' + b
suffix = '00' if a < c else '000'
print(prefix + suffix)
a < c will evaluate to either True or False. So you are effectively getting either print('000'[True:]) or print('000'[False:]).
When you have the [] after a string, those will perform a slice on the string. You'd see this in actually practice as something like the following (here's a link for more info:
'abcde'[2] # returns 'c', which, starting from zero, is 2nd item
'abcde'[0] # returns 'a', which is the zero-th item
'abcde'[1:3] # returns 'bc', starting from the 1st item and going to the 3rd, not inclusive of the third
It looks like if you use booleans in such a slice, the False acts as a 0 and True acts as a 1
"abcde"[True] == "abcde"[1] # evaluates to true, these are the same
'abcde'[True] # evaluates to 'b'
"abcde"[False] == "abcde"[2] # evaluates to `False`
"abcde"[True] == "abcde"[2] # evaluates to `False`
"abcde"[False] == "abcde"[0] # evaluates to True, because False is effectively 0 here
So, having a [True:] or [False:] in that string-slice is the same as having [1:] or '[0:]`, which is saying to "give all characters starting with the second (for True/1:) or first (for False/0:) in this string".
The string '000' has length 3. The boolean a < c has value False or True. The operation s[i] for a string s and integer i refers to the i'th element of s, and the operation s[i:] takes the substring of s from index i through the end of s. A boolean value will be converted to an integer in Python as follows: False becomes 0 and True becomes 1.
So, '000'[a < c:] is the same as '000'[0:] if a < c is False, and this is the same as '000'. If a < c is True, then '000'[a < c:] is the same as '000'[1:] which is '00'.
I was wondering if someone would be able to help me regarding my coding problem. I'm still a beginner and I may have missed something here.
Basically, the instruction says that I need to arrange 3 integers in ascending order.
e.g Input : 5 2 4 ------> Output : 2 4 5
I need to utilize the conditional statements for this. Here is what I've done so far.
a, b, c = input().split()
a = int (a)
b = int (b)
c = int (c)
if a < b and a < c:
smallest = a
elif b < a and b < c:
smallest = b
else:
smallest = c
if a > b and a < c:
middle = a
elif a < b and a > c:
middle = a
elif b > a and b < c:
middle = b
elif b < a and b > c:
middle = b
else:
middle = c
if a > b and a > c:
largest = a
elif b > a and b > c:
largest = b
else:
largest = c
print(smallest, middle, largest)
This is on CodeChum btw, I'm stuck in this because I can't figure out why it doesn't accept the code I did. Basically there are 5 tests that the code needs in order to submit the whole activity. I managed to do test 1-4 but for some reason it fails on test 5.
The problem is that your code does not react well if two numbers are identical. You should replace your strict inequalities with non-strict ones.
a = 3
b = 3
c = 1
if a > b and a < c:
middle = a
elif a < b and a > c:
middle = a
elif b > a and b < c:
middle = b
elif b < a and b > c:
middle = b
else:
middle = c
print(middle) # 1 when it should be 3
As a == b, none of the 4 conditions can be True, and therefore the middle number will always be c.
In order to support the case where a == b, we can add another condition:
elif a == b:
middle = a
else:
middle = c
we can simplify this code by replacing the strict inequalities with non-strict ones (⩽ , <= in Python):
if b <= a < c:
middle = a
elif b >= a > c:
middle = a
elif a < b < c:
middle = b
elif a > b > c:
middle = b
else:
middle = c
We simply said that if a == b, the middle is always a. I also simplified the structure for better readability.
Why don't you simply use sorted function?
This one results in the exact thing you are looking for.
smallest, middle, largest = sorted(map(int, input().split()))
print(smallest, middle, largest)
Note that you don't need the map to int function for this. But you if don't do that, the smallest, middle, largest variables will remain str objects.
As the input is guaranteed to contain exactly 3 numbers (separated by whitespace) you can just do this:
if (inval := input()):
if len(nums := inval.split()) == 3:
try:
lo, mid, hi = sorted(map(int, nums))
print(lo, mid, hi)
except ValueError:
pass
I'm trying to optimize my code by using dictionaries instead of if-elif statements.
I've read that you can optimize code by using dictionaries instead of if-elif statements, but I don't know how to do that. I'd like to use the logical expressions below somehow in the dictionary. (The code iterates through a and b)
def e_ha(n, t, a, b, E):
if a == b:
return 6
elif (a%n == 0, a != n**2, b == a + 1) == (True, True, True):
return 0
elif ((a-1)%n == 0, (a-1) != n**2, b == a - 1) == (True, True, True):
return 0
elif (a%n == 0, b == a-(n-1)) == (True, True):
return 1
elif (b%n == 0, a == b-(n-1)) == (True, True):
return 1
elif abs(a-b) == 1:
return 1
elif abs(a-b) == n:
return 1
else:
return 0
One naive approach to achieve the best performance is to build a big table storing the results for all possible (a, b) pairs. However, this could consume lots of memory and becomes inpractical for large ns.
Here is how the code can be optimized using a normal approach, as explained in the following step-by-step.
1. Using Explicit and for Logical Expressions
As suggested in the comments, this is much more readable and also more efficient because of the short circuiting behavior of and. This change alone reduces the runtime by 60% in my tests.
2. Remove Redundant Conditions
Since both a and b range from 1 to n**2, if a == n**2, then b == a + 1 can never be fulfilled. Therefore the a != n**2 check in the condition a%n == 0 and a != n**2 and b == a + 1 is redundant. The same applies to the third condition. Eliminating them simplifies these conditions to:
...
elif a % n == 0 and b == a + 1:
elif (a - 1) % n == 0 and b == a - 1:
...
3. Avoid Repeated Computations in Conditions
Note that the above-improved conditions
a % n == 0 and b == a + 1 and (a - 1) % n == 0 and b == a - 1 are special cases of abs(a - b) == 1. Therefore these conditions can be rewritten using nested if-else as follows.
if abs(a - b) == 1:
if a % n == 0 and b > a: return 0
elif b % n == 0 and a > b: return 0 # a - 1 equals to b here so it is replaced to save one computation
else return 1
Also note that the value abs(a - b) is related to all the conditions. Therefore it can be computed before all conditions are checked. With this change, the code becomes
d = abs(a - b)
if d == 0: return 6
elif d == 1:
if a % n == 0 and b > a: return 0
elif b % n == 0 and a > b: return 0
else return 1
elif d == n - 1:
if a % n == 0 and a > b: return 1
elif b % n == 0 and b > a: return 1
else return 0
elif d == n: return 1
else: return 0
4. Simplify Logic
For example, the first nested if-else above can be simplified to
if min(a, b) % n == 0: return 0
else return 1
A more compact syntax is:
return 1 if min(a, b) % n == 0 else 0
5. Apply Python-specific Optimizations
In Python, the number 0 is regarded as having a falsy value. So for numbers if d != 0: and if d == 0: are equivalent to if d: and if not d: respectively. The latter is a bit faster. Applying this change results in the following optimized code (here a more compact syntax is used to shorten the answer).
d = abs(b - a)
if not d: return 6
elif d == 1: return 1 if min(a, b) % n else 0
elif d == n - 1: return 0 if max(a, b) % n else 1
else: return 1 if d == n else 0
Applying steps 2 to 5 above reduces the runtime by another 50%.
6. Adjust Order of Conditions based on Input Distribution
This change relies on the knowledge of the actual input distribution in the application. The target is to make the more frequently seen inputs return faster. In this example, assume the inputs a and b are uniformly distributed within [1, n**2] and n >= 10. In this case, the most frequent scenario is that the value d does not match any of the if conditions and 0 is returned at the end after all conditions are checked. In order to speedup, we can make it fail faster by first checking whether d can possibly lead to a non-zero return value.
d = abs(a - b)
if 1 < d < n - 1 or d > n: return 0 # Return 0 if d is not in [0, 1, n - 1, n]
elif d == 1: return 1 if min(a, b) % n else 0
elif d == n - 1: return 0 if max(a, b) % n else 1
else: return 1 if d == n else 6 # d == 0 case is moved to the last "else" since it is least frequently seen
7. Using Lookup Tables
Further speedup can be achieved by using lookup tables. Here, the values [0, 1, n - 1, n] for the first conditional check can be stored to speedup the check. In this case, there are two primary options for this: a set or a length-n+1 list of boolean values. The former uses less memory while the latter has better performance. Note that the lookup table should be constructed once outside the function and passed into it. The code using a boolean list as a lookup is as follows:
def func(n, a, b, lookup):
d = abs(a - b)
if not (d <= n and lookup[d]): return 0
...
Applying steps 6 and 7 (with boolean list lookup) reduces the runtime by another 15%.
Note that in this example a 2D lookup table (implemented as nested lists or dictionaries) can also be applied using (min(a, b) % n, d) as indices. However, under the same assumption of input distribution in step 6, this is slightly slower than a 1D lookup because of the overhead of one extra level of indexing.
The runtime above is the total time of applying the function to all possible (a, b) values within [1, n**2] for n=20.
Using a dictionary, where the keys are boolean expressions is not going to work the way you hope it does. There is no such thing as a boolean-expression-object that could take the place of the key, only booleans. In the end, boolean expressions evaluate to either True or False, so at most you could only have two key-value pairs.
I would suggest, however, you make things a bit more readable/pythonic:
if a%n == 0 and a != n**2 and b == a + 1:
or
if all((a%n == 0, a != n**2, b == a + 1)):
You can just use a list of tuples and loop through it:
def e_ha(n, t, a, b, E):
checks = [
(a == b, 6),
(all(a%n == 0, a != n**2, b == a + 1), 0 ),
(all((a-1)%n == 0, (a-1) != n**2, b == a - 1), 0),
(all(a%n == 0, b == a-(n-1)), 1),
(all(b%n == 0, a == b-(n-1)), 1 ),
(abs(a-b) == 1, 1),
(abs(a-b) == n, 1),
(true, 0)
]
for valid, return_value in checks:
if valid:
return return_value
Caveat:
This is most certainly not faster in any way. Timed it multiple times and it was always slower.
It is less readable than the alternative
I am trying to find the great common divisor by using a function and solving it iteratively. Though, for some reason, I am not sure why I am not getting the right output.
The greatest common divisor between 30 & 15 should be 15, however, my output is always giving me the wrong number. I have a strong feeling that my "if" statement is strongly incorrect. Please help!
def square(a,b):
'''
x: int or float.
'''
c = a + b
while c > 0:
c -= 1
if a % c == 0 and b % c == 0:
return c
else:
return 1
obj = square(30,15)
print (obj)
You should return a value only if you finished iterating all numbers and found none of them a divisor to both numbers:
def square(a, b):
c = a + b
while c > 0:
if a % c == 0 and b % c == 0:
return c
c -= 1
return 1
However, the last return will be unneeded in this case, as c would go from a + b to 1, and mod 1 will always bring a common divisor, so the loop will always terminate with 1, for the worst case.
Also, a number greater than a and b can not be a common divisor of them. (x mod y for y > x yields x), and gcd is the formal name for the task, so I would go with
def gcd(a, b):
for c in range(min(a, b), 0, -1):
if a % c == b % c == 0:
return c
for iterational solution.
You might be interested to know that there is a common recursive solution to the GCD problem based on the Euclidian algorighm.
def gcd(a, b):
if b == 0:
return a
else:
return gcd(b, a % b)
print(gcd(30, 15))
# 15