How to check if a dictionary is empty? - python

I am trying to check if a dictionary is empty but it doesn't behave properly. It just skips it and displays ONLINE without anything aside from the display the message. Any ideas why ?
def isEmpty(self, dictionary):
for element in dictionary:
if element:
return True
return False
def onMessage(self, socket, message):
if self.isEmpty(self.users) == False:
socket.send("Nobody is online, please use REGISTER command" \
" in order to register into the server")
else:
socket.send("ONLINE " + ' ' .join(self.users.keys()))

Empty dictionaries evaluate to False in Python:
>>> dct = {}
>>> bool(dct)
False
>>> not dct
True
>>>
Thus, your isEmpty function is unnecessary. All you need to do is:
def onMessage(self, socket, message):
if not self.users:
socket.send("Nobody is online, please use REGISTER command" \
" in order to register into the server")
else:
socket.send("ONLINE " + ' ' .join(self.users.keys()))

Here are three ways you can check if dict is empty. I prefer using the first way only though. The other two ways are way too wordy.
test_dict = {}
if not test_dict:
print "Dict is Empty"
if not bool(test_dict):
print "Dict is Empty"
if len(test_dict) == 0:
print "Dict is Empty"

d = {}
print(len(d.keys()))
If the length is zero, it means that the dict is empty.

Simple ways to check an empty dict are below:
a = {}
if a == {}:
print ('empty dict')
if not a:
print ('empty dict')
Method 1 is more strict, because when a = None, method 1 will provide the correct result, but method 2 will give an incorrect result.

A dictionary can be automatically cast to boolean which evaluates to False for empty dictionary and True for non-empty dictionary.
if myDictionary: non_empty_clause()
else: empty_clause()
If this looks too idiomatic, you can also test len(myDictionary) for zero, or set(myDictionary.keys()) for an empty set, or simply test for equality with {}.
The isEmpty function is not only unnecessary but also your implementation has multiple issues that I can spot prima-facie.
The return False statement is indented one level too deep. It should be outside the for loop and at the same level as the for statement. As a result, your code will process only one, arbitrarily selected key, if a key exists. If a key does not exist, the function will return None, which will be cast to boolean False. Ouch! All the empty dictionaries will be classified as false-nagatives.
If the dictionary is not empty, then the code will process only one key and return its value cast to boolean. You cannot even assume that the same key is evaluated each time you call it. So there will be false positives.
Let us say you correct the indentation of the return False statement and bring it outside the for loop. Then what you get is the boolean OR of all the keys, or False if the dictionary empty. Still you will have false positives and false negatives. Do the correction and test against the following dictionary for an evidence.
myDictionary={0:'zero', '':'Empty string', None:'None value', False:'Boolean False value', ():'Empty tuple'}

1st Way
len(given_dic_obj)
It returns 0 if there are no elements.
Else, returns the size of the dictionary.
2nd Way
bool(given_dic_object)
Returns False if the dictionary is empty, else return True.

You can also use get(). Initially I believed it to only check if key existed.
>>> d = { 'a':1, 'b':2, 'c':{}}
>>> bool(d.get('c'))
False
>>> d['c']['e']=1
>>> bool(d.get('c'))
True
What I like with get is that it does not trigger an exception, so it makes it easy to traverse large structures.

use 'any'
dict = {}
if any(dict) :
# true
# dictionary is not empty
else :
# false
# dictionary is empty

Related

I can't figure out what is wrong with this function?

This is what it should return
Returns True if all items are truthy.
Examples:
>>> all_true([1, True, 'oregonstate'])
True
>>> all_true([0, 1, 2])
False
"""
This is what I have written
def all_true(items):
for i in items:
if i == True:
return True
else:
return False
pass
Not sure why it is not working, can someone help?
Your function just returns the truthiness of the first item in the list, since it always returns on the first iteration.
You want to do something like this:
def all_true(items):
for i in items:
if not i:
return False
return True
Note that this all_true function already exists in Python. It is the the built-in all function.
Two problems. First, you are returning on the first True thing. In fact, you are returning either True or False on the first thing, regardless. Since you return on both the if and its else clauses, the loop will always return on the first iteration. A bit more subtle, but if there aren't any values in the list, it will return None.
Second, if you want "truthy", don't compare specifically to True. foo == True is False. Instead, just let the if do the boolean test
def all_true(items):
for i in items:
if not i:
return False
return True
all and any are builtin functions that do the same thing. It would generally be preferable to use them.
"All items are truthy" is logically equivalent to "no items are falsy."
def all_true(items):
for i in items:
if not i:
return False
return True
Because 0 is falsy. Also there's no need to implement your own function for that, use Python's built–in all() function instead!

Why does it display "local variable referenced before assignment" even I have assigned it in the same function?

def p3(x,y,ls2):
for i in ls2:
if abs(i[0]-x)==abs(i[1]-y):
c=0
break
else:
c=1
if c==0:
return False
else:
return True
Even I have assigned c in the same function, it still displays "local variable 'c' referenced before assignment"
As the comment by Suraj S says, the problem is if ls2 is an empty list (iterable). Even if that were not a problem, c is a local variable inside the for loop and even though Python allows accessing it outside its scope, it is not a good practice to do so. So it is correct to default initialize it first before running the loop. You can default it to 0 or 1 depending on your use case.
Also, practice Boolean Zen. Don't make redundant checks with booleans. It is better to use True and False instead of 0 and 1.
def p3(x,y,ls2):
c = True # default
for i in ls2:
if abs(i[0]-x)==abs(i[1]-y):
c = False
break
# no need for else at all
return c
Even better:
def p3(x,y,ls2):
for i in ls2:
if abs(i[0]-x)==abs(i[1]-y):
return False
# no need for else at all
return True
If I understand correctly your function, you could simplify it to the following:
def p3(x, y, ls2):
# if no list or list is empty
if not ls2: # the condition could be more convoluted if needed
return 'invalid input' # or return boolean depending on use case
for i in ls2:
# if condition is matched return immediately
if abs(i[0]-x)==abs(i[1]-y):
return False
# the condition was not matched in loop, return default True
return True
You could even simplify more using all that will stop prematurely if the condition is met:
def p3(x, y, ls2):
# if no list or list is empty
if not ls2: # the condition could be more convoluted if needed
return 'invalid input' # or return boolean depending on use case
return all(abs(i[0]-x)!=abs(i[1]-y) for i in ls2)
# or: return not any(abs(i[0]-x)==abs(i[1]-y) for i in ls2)
In general, if you instantiate a variable (namely c) inside of a for loop, it's best not to use that variable outside of that for loop.
The practical reason for this is that you can't be sure that for loop will run and so the variable might not get instantiated. The more high-level reason is to maintain a sense of scope in your code, or "what happens in the for loop, stays in the for loop", if you will.
So in your case, I would recommend instantiating c with a 'default' value (depending on what your logic is) before the for loop starts, so that even if the for loop runs 0 times, c still has a value.
Alternatively, this entire function could be implemented as
def p3(x, y, ls2):
return not any([abs(i[0]-x)==abs(i[1]-y) for i in ls2])

How to pass dictionary key as function argument in Python

I'm a python and programming beginner and I've been trying to create a function to check whether a given key exists inside a dictionary or not and retrun boolean. This topic was helpful but did not solve my function parameter problem.
I found many topics related to passing a dictionary as argument in a function but none stating how to do so with a key, couldn't find an answer to my specific problem in here.
When I use my code inside the main program, it works fine:
if "myKey" in myDict:
answ = True
print(myKey, " is there!")
else:
answ = False
print(myKey, " is not there.")
However, trying to make a function of it and then calling it doesn't work, it doesn't return an error either, just nothing happens nor gets printed.
def checkIfThere(myKey, myDict):
#for i in myDict:
if myKey in myDict:
return True
print(myKey, "is there!")
else:
return False
print(myKey, "is not there.")
That I've tried calling with the following:
checkIfThere("thisIsAKey", myDict)
checkIfThere(thisIsAKey, myDict)
checkIfThere("\"thisIsAKey\"", myDict)
What am I missing?
Is it just not feasible to pass a dictionary key as argument to a function?
The problem is that your function will stop execution, and return control to the caller, when it encounters a return statement. Note, you are also discarding the return value (since you don't assign the result of the call to a variable).
Consider:
>>> def some_func(x):
... return
... print(x)
...
>>> y = some_func(42)
Notice, the print function never ran.
Generally, you should let the function do the work, and let the caller do the printing. So, your function could be written (in a more streamlined manner):
>>> def check_if_there(key, adict):
... return key in adict
...
>>> is_in = check_if_there('a', {'b':2})
>>> print(is_in)
False
Notice, this function's responsibility is simply to check if a key in a dict. As you learn to program, you will find it useful to split functions into re-usable, composable parts. So, another function could have the reponsibility of printing:
>>> def tell_if_there(key, adict):
... if check_if_there(key, adict):
... print(key, " is there!")
... else:
... print(key, " is not there.")
...
>>> tell_if_there('a', {'b':2})
a is not there.
>>> tell_if_there('b', {'b':2})
b is there!
Your functions works fine!
But the print statement should be outside of the function. Try this.
1) Define your function without print statement
def checkIfThere(myKey, myDict):
for i in myDict:
if myKey in myDict:
return True
else:
return False
This will return True or False depending on myKey is one of the keys of myDict.
2) Then, run the followings.
if checkIfThere(myKey, myDict):
print(myKey, " is there!")
else:
print(myKey, " is not there.")
This will print myKey is there if the function above returns True; otherwise myKey is not there.
Thank you.
The problem with your function is that you are returning from the function before printing anything.
You could remove the return statement from your function in order to make it work.

Test for list without duplicated elements

There aren't a set of instructions, but I basically have to write a code for def hasNoDuplicate and it returns True exactly when list has no duplicates. This is what I've written, I'm new to programming so all of this is very overwhelming. I don't know exactly what to put in the if statement. Any advice would help a lot!
def hasNoDuplicates(values):
foundCounterExampleYet = False
for value in values:
if():
foundCounterExampleYet = True
return not(foundCounterExampleYet)
def hasNoDuplicates(values):
foundCounterExampleYet = False
value = None
while values:
value = values.pop()
if value in values:
foundCounterExampleYet = True
break
return not(foundCounterExampleYet)
Now you get:
>>> hasNoDuplicates([1,2,3])
True
>>> hasNoDuplicates([1,2,3,4,6,7,8,9,4])
False
>>>
What this code does is, it takes the input list, and one by one takes out the last element from the list and checks if the item exists in the list. If it exists, then a duplication is detected, and it changes the value of foundCounterExampleYet and consequently jumps out of the loop. This checking happens until the list becomes empty. while values means do this while the list is not empty
The pop method takes out the last element from the list. But it has side effect, meaning it changes the value of the initial input:
>>> [1,2,3].pop()
3
>>> a = [1,2,3]
>>> a.pop()
3
>>> a
[1, 2]
You're on the right track. You can store the values in a set as you're looping through the inputs, and use the in operator to check for membership in that set. See my comments alongside the following code.
def hasNoDuplicates(values):
currentValues = set() # initialize an empty set
for value in values: # iterate over your inputs
if value in currentValues: # if the current value is in your set, there is a duplicate
return False
else:
currentValues.add(value) # no duplicate exists, add it to the set
return True # If it made it through all the values, there were no duplicates
For fun, there is an easier way to do this. If the items in the values sequence are hashable, you can make a set from the whole sequence. Since by definition a set may not have any duplicates, if the length of the original sequence is the same length as the set, then all items are unique. If the set is shorter, there was at least one duplicate.
def hasNoDuplicates(values):
return len(values) == len(set(values))

Function doesn't stop after "return(False)"

I am trying to write a function which is supposed to compare list structures (the values are indifferent). The problem is that I have two lists which are unequal but the function still returns True even though it actually goes into the else part. I don't understand why and what I did wrong. Here is my code:
def islist(p): #is p a list
return type(p)==type(list())
def ListeIsomorf(a,b):
if len(a)==len(b):
for i,j in zip(a,b):
if islist(i) and islist(j):
ListeIsomorf(i,j)
elif islist(i) or islist(j):
return(False)
return(True)
else:
print(a,"length from the list isn't equal",b)
return(False)
#example lists
ListeE = [[],[],[[]]]
ListeD = [[],[],[[]]]
ListeF = [[[],[],[[]]]]
ListeG = [[],[[]],[[]]]
ListeH = [1,[3]]
ListeI = [1,3]
#tests
print(ListeIsomorf(ListeD,ListeE)) # True
print(ListeIsomorf(ListeD,ListeF)) # False
print(ListeIsomorf(ListeD,ListeG)) # False
print(ListeIsomorf(ListeH,ListeI)) # False
So the problem only occurs with the third print(ListeIsomorf(ListeD,ListeG)) # False. It actually goes into the else part and does print the "length from the list isn't equal" but it doesn't stop and it doesn't give out the return(False). Am I missing something?
The problem is that when your function calls itself recursively:
ListeIsomorf(i,j)
it ignores the returned value.
Thus the comparisons that take place at the second level of recursion have no effect on what the top level returns.
Changing the above to:
if not ListeIsomorf(i,j):
return(False)
fixes the problem.

Categories