Is there a shorter way to do exactly this? - python-3.x

I'm trying to find away to do this in a shorter way I don't like not using else in the end because it looks weird without it. This works for me for some reason. If I add the, " else: return True" it will only look at the first true from the list and then return True but won't check the rest... and will end the function
b = [[True, True, True], [True, True, True], [True, True, False]]
for i in range(3):
for j in range(3):
if b[i][j] == False:
return False
return True

I guess a pretty short way to accomplish this would be:
return all(i for l in b for i in l)

You can use either all or any to do this:
all(all(x) for x in b)
OR
not any(not y for x in b for y in x)
In either case, the value of the expression will be the same as the return value of your original function. Like your original loop, both of these expressions are short-circuiting: they will stop as soon as a False element in encountered in the nested lists.
In your original code, returning True on the first element naturally ends the function. That's just how return works. If you absolutely must have an else clause to please your inner aesthete (I would recommend against it), use else: continue instead. This is totally superfluous (and therefore generally undesirable), but it will instruct the loop to continue until a False is found instead of returning from the function immediately.

Related

Confusion about boolean values of numbers other than 0 and 1 in python [duplicate]

I just learned there are truthy and falsy values in python which are different from the normal True and False.
Can someone please explain in depth what truthy and falsy values are? Where should I use them? What is the difference between truthy and True values and falsy and False values?
We use "truthy" and "falsy" to differentiate from the bool values True and False. A "truthy" value will satisfy the check performed by if or while statements. As explained in the documentation, all values are considered "truthy" except for the following, which are "falsy":
None
False
Numbers that are numerically equal to zero, including:
0
0.0
0j
decimal.Decimal(0)
fraction.Fraction(0, 1)
Empty sequences and collections, including:
[] - an empty list
{} - an empty dict
() - an empty tuple
set() - an empty set
'' - an empty str
b'' - an empty bytes
bytearray(b'') - an empty bytearray
memoryview(b'') - an empty memoryview
an empty range, like range(0)
objects for which
obj.__bool__() returns False
obj.__len__() returns 0, given that obj.__bool__ is undefined
As the comments described, it just refers to values which are evaluated to True or False.
For instance, to see if a list is not empty, instead of checking like this:
if len(my_list) != 0:
print("Not empty!")
You can simply do this:
if my_list:
print("Not empty!")
This is because some values, such as empty lists, are considered False when evaluated for a boolean value. Non-empty lists are True.
Similarly for the integer 0, the empty string "", and so on, for False, and non-zero integers, non-empty strings, and so on, for True.
The idea of terms like "truthy" and "falsy" simply refer to those values which are considered True in cases like those described above, and those which are considered False.
For example, an empty list ([]) is considered "falsy", and a non-empty list (for example, [1]) is considered "truthy".
See also this section of the documentation.
Python determines the truthiness by applying bool() to the type, which returns True or False which is used in an expression like if or while.
Here is an example for a custom class Vector2dand it's instance returning False when the magnitude (lenght of a vector) is 0, otherwise True.
import math
class Vector2d(object):
def __init__(self, x, y):
self.x = float(x)
self.y = float(y)
def __abs__(self):
return math.hypot(self.x, self.y)
def __bool__(self):
return bool(abs(self))
a = Vector2d(0,0)
print(bool(a)) #False
b = Vector2d(10,0)
print(bool(b)) #True
Note: If we wouldn't have defined __bool__ it would always return True, as instances of a user-defined class are considered truthy by default.
Example from the book: "Fluent in Python, clear, concise and effective programming"
Truthy values refer to the objects used in a boolean context and not so much the boolean value that returns true or false.Take these as an example:
>>> bool([])
False
>>> bool([1])
True
>>> bool('')
False
>>> bool('hello')
True
Where should you use Truthy or Falsy values ?
These are syntactic sugar, so you can always avoid them, but using them can make your code more readable and make you more efficient.
Moreover, you will find them in many code examples, whether in python or not, because it is considered good practice.
As mentioned in the other answers, you can use them in if tests and while loops. Here are two other examples in python 3 with default values combined with or, s being a string variable. You will extend to similar situations as well.
Without truthy
if len(s) > 0:
print(s)
else:
print('Default value')
with truthy it is more concise:
print(s or 'Default value')
In python 3.8, we can take advantage of the assignment expression :=
without truthy
if len(s) == 0:
s = 'Default value'
do_something(s)
with truthy it is shorter too
s or (s := 'Default value')
do_something(s)
or even shorter,
do_something(s or (s := 'Default value'))
Without the assignment expression, one can do
s = s or 'Default value'
do_something(s)
but not shorter. Some people find the s =... line unsatisfactory because it corresponds to
if len(s)>0:
s = s # HERE is an extra useless assignment
else:
s = "Default value"
nevertheless you can adhere to this coding style if you feel comfortable with it.
Any object in Python can be tested for its truth value. It can be used in an if or while condition or as operand of the Boolean operations.
The following values are considered False:
None
False
zero of any numeric type, for example, 0, 0L, 0.0, 0j.
any empty sequence, for example, '', (), [].
any empty mapping, for example, {}.
instances of user-defined classes, if the class defines a __nonzero__() or __len__() method, when that method returns the integer zero or bool value False.
All other values are considered True -- thus objects of many types are always true.
Operations and built-in functions that have a Boolean result always return 0 or False for false and 1 or True for true, unless otherwise stated.
In case of if (!id) {}
!expr returns false if its single operand can be converted to true; otherwise, returns true.
If a value can be converted to true, the value is so-called truthy. If a value can be converted to false, the value is so-called falsy.
Examples of expressions that can be converted to false are:
null;
NaN;
0;
empty string ("" or '' or ``);
undefined.
Even though the ! operator can be used with operands that are not Boolean values, it can still be considered a boolean operator since its return value can always be converted to a boolean primitive. To explicitly convert its return value (or any expression in general) to the corresponding boolean value, use a double NOT operator or the Boolean constructor.
Example:
n1 = !null // !t returns true
n2 = !NaN // !f returns true
n3 = !'' // !f returns true
n4 = !'Cat' // !t returns false
While in case of if (id != null) {} it will only check if the value in id is not equal to null
reference https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_NOT
Falsy means something empty like empty list,tuple, as any datatype having empty values or None.
Truthy means :
Except are Truthy

canConstruct a memorization dynamic programming problem

I am stating to solve some dynamical programming problem, I came across the problem to solve if a string can be constructed from a list of string.
I have use this following method in python 3.8.
def canConstruct(target,workbank,memo={}):
if (target in memo):
return(memo[target])
if len(target)==0:
return(True)
for i in range (len(workbank)):
pos=target.find(workbank[i])
if (pos != -1):
suffix=target[pos:pos+len(workbank[i])]
out=canConstruct(suffix,workbank,memo)
if (out==True):
memo[target]=True
return(True)
memo[target]=False
return(False)
print(canConstruct('aabbc',['aa','b','c']))
instead of getting true I am getting the error maximum recursion depth exceeded in comparison.
I have checked my recursion limit it is 1000.
Can anyone tell me if I am doing anything wrong.
Thank you in advance.
Ok, there are few pitfalls in your code.
The main issue was, the for loop, because every time it calls the function, it started a new loop, hence the index of i was always one, this was creating the maximum recursion depth error.
The memo parameter, was been redundant to make it as a Dictionary,better in this case as a List.
This suffix=target[pos:pos+len(workbank[i])] had wrong position, it is supposed to be:
suffix = target[len(workbank[idx]):]]
Becase you need to leave behind was is already call and move forward right?
You were doing [0:2] which is 'aa' again. Insted you should do [2:] which is bbc
Solution
Note: I create as I understood the issue, if you expect a different output, please let me know in a comment below.
def canConstruct(target,workbank,memo=[], idx=0):
pos = target.find(workbank[idx])
if pos != -1:
memo.append(True)
idx += 1
try:
suffix = target[len(workbank[idx]):]
canConstruct(suffix,workbank,memo, idx)
except IndexError: # Here we exit the recursive call
pass
else: # In case it did not find string, append False
memo.append(False)
return all(memo) # in order to be True, all item in memo must be True
print(canConstruct('aabbc',['aa','bb','c']))
Output
# True
def canConstruct(target, wordbank, memo=None):
if memo is None:memo={}
if target in memo:return memo[target]
if target == '':return True
for word in wordbank:
if target.startswith(word):
suffix = target.replace(word, '', 1)
if canConstruct(suffix, wordbank, memo) == True:
memo[target] = True
return True
memo[target] = False
return False

Python: Check if tuple contain only integers with while

I have a task to define a function contains_only_integers which takes a tuple as the argument and returns True is every element of the tuple is an integer, and false otherwise. I'm a bit stuck on why I get false every time.
I would use a for-loop, but the task asks specifically for a while loop.
def contains_only_integers(tup):
while isinstance(tup, int)==True:
return True
else:
return False
What am I missing?
Mthrsj covered your problem and how to fix it but an alternative, perhaps more pythonic, way of doing this would be to use the builtin all function.
def contains_only_integers(tup):
return all(isinstance(v, int) for v in tup)
When you do while isintance(tup,int), the function evaluates the tuple, not each element. To achieve what you want, you need to iterate over the tuple. An example below:
def contains_only_integers(tup):
for item in tup:
if not isinstance(item, int):
return False
return True
If the code find any item in the tuple that is not an integer instance it will return False. Otherwise, it will return True.
EDIT
As you said you need to use a while loop, there it is:
def contains_only_integers(tup):
i = 0
while i < len(tup):
if not isinstance(tup[i], int):
return False
i+=1
return True

How should I obtain an appropriate boolean result?

I've written some code and here's a short bit
x = ['apple, iphone','samsung, galaxy','oneplus, 10pro']
print('apple' in x)
how do I get this statement as true, since apple already exists in x, I still keep getting the False as the boolean value.
When the in operator is applied to a list like you have here it looks for an exact match in the list. Your code is returning false because 'apple' isn't in the list, 'apple, iphone' is. To check each element in the list for the substring 'apple' you could use list comprehension. Something like:
x = ['apple, iphone','samsung, galaxy','oneplus, 10pro']
print(True in ['apple' in s for s in x])
What the second line does is use list comprehension to build a list of booleans indicating if the substring 'apple' is in that element. Then it checks if True is in the resulting list.
or instead of using the in operator:
x = ['apple, iphone','samsung, galaxy','oneplus, 10pro']
print(any(['apple' in s for s in x]))
The any built-in function returns true if any element in an iterable is True.
x = ['apple, iphone','samsung, galaxy','oneplus, 10pro']
print(True in ('apple' in d for d in x))
Maybe use a function like this:
IsItemInList(item, list):
for x in list:
if x == item:
return True
return False
Pretty sure theres a much cleaner way to do this but that was my first guess. As we know, the first is mostly the worst.

Is there a way to return true for an empty list in a sort invariant?

So I am supposed to write a function that returns true if the said sequence is arranged from smallest to largest. I am able to understand strings and num lists but for an empty list, I am unable to understand why it won't return as true.
This is for understanding and possibly help me understand how to manipulate my loops better.
def is_sorted(seq):
for i in range(0, len(seq)):
if seq[i]<seq[i+1]:
return True
else:
return False
print(is_sorted([])) # expected to be true but returns none
The obvious problem is that with an empty list you are returning None which evaluates to false. The other problem is that you are using return inside of a loop, which means that you aren't evaluating every sequence in the iterable.
#hiro protagonist's answer is one solution to this problem. I offer my alternative using all and a generator expression.
def is_sorted(seq):
return all(seq[i] < seq[i + 1] for i in range(len(seq) - 1))
# All evaluate True
print(is_sorted(['a', 'b', 'c']))
print(is_sorted([1, 2, 3]))
print(is_sorted([]))
# Both evaluate False
print(is_sorted(['a', 'c', 'b']))
print(is_sorted([0, 1, -1]))
Edit with explanation
As best I understand it, all works by stepping through an iterable and returns False if any value in it evaluates to False, otherwise returning True.
As the comments may show you, I don't have a good understanding of Python generators. A generator is an iterable object that calculates the next value and yields it back each time it is referenced.
The generator defined above, each time that all references it, calculates seq[i] < seq[i + 1] and gives that value back. If this is False at any time then all will return False.
I hope this helps. I'm sure one of the good people in the comments will correct any flawed understanding that I have.
Your implementation is wrong. It will return True for [1, 3, 2] since it only compares the first 2 elements (return returns after the first iteration).
It can be fixed by checking for the opposite condition, then return True after the loop.
You should also iterate until len(seq) - 1 otherwise the last iteration will cause an IndexError.
def is_sorted(seq):
for i in range(0, len(seq) - 1):
if seq[i] > seq[i + 1]:
return False
return True
print(is_sorted([1, 2, 3]))
# True
print(is_sorted([1, 3, 2]))
# False
print(is_sorted([]))
# True
And of course there is the trivial, naive solution,
def is_sorted(seq):
return seq == sorted(seq)
this is a variant that also works for empty lists and lists of length 1:
from itertools import islice
def is_sorted(seq):
return all(i <= j for i, j in zip(seq, islice(seq, 1, None)))
it iterates over seq[k] and seq[k+1] using zip and islice. and only if all elements satisfy the requirement True will be returned.
Its because for an empty list the code inside the for is not reached. So neither return statement isnt reached. Also you should take into account that a list with only one element should also return True. Solution:
def is_sorted(seq):
for i in range(0, len(seq)-1):
if seq[i]>=seq[i+1]:
return False
return True

Resources