checking if key's already in dictionary with try except - python

I'm using a dictionary to count how many times different items appear in a dataset. In the init of the class, I create the property as a dictionary like this
self.number_found = {}
The first time I find any particular item, I would get a KeyError if I try to do this because the item isn't in the dictionary yet
self.number_found[item] = 1
so I ended up creating a function that checks if an entry is already in the dictionary and if not, adds it for the first time
def _count_occurrences(self, item):
try:
#this checks to see if the item's already in the dict
self.number_found[item] = self.number_found[item] + 1
x = self.number_found[item]
except KeyError:
x = 1
#this adds an item if not in the dict
self.number_found[item] = x
return x
However, this is not working as intended if I find a second occurrence of an item in a dataset.
Let's say there are two 'elephant' in my dataset. When I print self.number_found to the console this is what I get
{'elephant': 1}
{'elephant': None}
and I get this error when adding the second occurrence
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
Question: what's the right way to check if the key's already in the dictionary (with an explanation as to why the 1 is changing to a None)

You can use a defaultdict:
from collections import defaultdict
self.number_found = defaultdict(int)
The first time an item is accessed, its value will take a default of 0
A None is returned because you're not returning anything in your try branch

The return at the end of the except block must be moved out. That way, x is returned for both cases
class C(object):
def __init__(self):
self.number_found = {}
def _count_occurrences(self, item):
try:
#this checks to see if the item's already in the dict
self.number_found[item] = self.number_found[item] + 1
x = self.number_found[item]
except KeyError:
x = 1
#this adds an item if not in the dict
self.number_found[item] = x
return x
c = C()
r = c._count_occurrences('elephant')
print r
print c.number_found
r = c._count_occurrences('elephant')
print r
print c.number_found
Here is a test run first with outdented return, then with it where you have it in your OP:
jcg#jcg:~/code/python/stack_overflow$ python number_found.py
1
{'elephant': 1}
2
{'elephant': 2}
jcg#jcg:~/code/python/stack_overflow$ python number_found.py
1
{'elephant': 1}
None
{'elephant': 2}
As you can see, the second version returns None since there is no return from the _count_occurrences try block

Related

Function to check if dictionary value is occupied

I'm trying to make a function to check whether a value added to a dictionary already exists.
If a value is already in the dictionary, it should print "Occupied" and not add the value to the existing key.
I have tried to get it to not append when the new input is similar, but it still adds the new input even though it is the same as the previous.
For example, if I add input_v as "Hi" --> XO = {'key': ["Hi"]}
If I were to put in "Hi" again, I then want it to say "Occupied", but as of right now it still adds to the dictionary.
XO = {'key': []}
def check_values(input_v):
value = input_v
print(XO)
if value in XO.values():
print("Occupied")
else:
XO['key'].append(value)
The issue is in the way you referenced the value of the 'key'. Use this:
XO = {'key': []}
def check_values(input_v):
value = input_v
global XO
#print(XO)
if value in XO['key']:
print("Occupied")
else:
XO['key'].append(value)
#print(XO)
d = dict()
for c in a:
if c not in d:
d[c] = 1
else:
print("Occupied")
Would this work? a is a list in this example.

How to skip a line of code based on certain condition? python dictionary min [duplicate]

This question already has answers here:
How to check if a dictionary is empty?
(9 answers)
Closed 1 year ago.
in python:
dic = {} #start with an empty list
After this line, I did a series of command to add things to the dic. But there is also a situation where nothing is added. Then, I need to use the value in the dic.
a = min(dic, key=dic.get)
if there is nothing in the dic, it will give me an error:
ValueError: min() arg is an empty sequence I don't need an output for a if dic is empty, so I then attempted to use the if statement to get away:
if dic == None:
pass
else:
a = min(dic, key=dic.get)
but this will still give me the same error. Is there a way to skip this line of codea = min(dic, key=dic.get)when dic = {}?
The dic is of the <class dict> whereas the None object is of the <class 'Nonetype'>.
So the given expression dic == Nonewill always return False.
Instead change it to dic == {} or len(dic) == 0 or simply dic.
An empty dictionary will usually evaluate to False.
if dic:
pass
else:
a = min(dic, key=dic.get)
Try changing the logic to:
if len(dic) == 0:
pass
else:
a = min(dic, key=dic.get)
You current code skips over the pass block because even if the dict dic is empty, it is not None, there's a bunch of ways to check emptiness of a dict, personally, I'm a fan of checking the len as above but there are other way such as on this page.

Return next key of a given dictionary key, python 3.6+

I am trying to find a way to get the next key of a Python 3.6+ (which are ordered)
For example:
dict = {'one':'value 1','two':'value 2','three':'value 3'}
What I am trying to achieve is a function to return the next key. something like:
next_key(dict, current_key='two') # -> should return 'three'
This is what I have so far:
def next_key(dict,key):
key_iter = iter(dict) # create iterator with keys
while k := next(key_iter): #(not sure if this is a valid way to iterate over an iterator)
if k == key:
#key found! return next key
try: #added this to handle when key is the last key of the list
return(next(key_iter))
except:
return False
return False
well, that is the basic idea, I think I am close, but this code gives a StopIteration error. Please help.
Thank you!
An iterator way...
def next_key(dict, key):
keys = iter(dict)
key in keys
return next(keys, False)
Demo:
>>> next_key(dict, 'two')
'three'
>>> next_key(dict, 'three')
False
>>> next_key(dict, 'four')
False
Looping while k := next(key_iter) doesn’t stop correctly. Iterating manually with iter is done either by catching StopIteration:
iterator = iter(some_iterable)
while True:
try:
value = next(iterator)
except StopIteration:
# no more items
or by passing a default value to next and letting it catch StopIteration for you, then checking for that default value (but you need to pick a default value that won’t appear in your iterable!):
iterator = iter(some_iterable)
while (value := next(iterator, None)) is not None:
# …
# no more items
but iterators are, themselves, iterable, so you can skip all that and use a plain ol’ for loop:
iterator = iter(some_iterable)
for value in iterator:
# …
# no more items
which translates into your example as:
def next_key(d, key):
key_iter = iter(d)
for k in key_iter:
if k == key:
return next(key_iter, None)
return None
You can get the keys of the dictionary as list and use index() to get the next key. You can also check for IndexError with try/except block:
my_dict = {'one':'value 1','two':'value 2','three':'value 3'}
def next_key(d, key):
dict_keys = list(d.keys())
try:
return dict_keys[dict_keys.index(key) + 1]
except IndexError:
print('Item index does not exist')
return -1
nk = next_key(my_dict, key="two")
print(nk)
And you better not use dict, list etc as variable names.
# Python3 code to demonstrate working of
# Getting next key in dictionary Using list() + index()
# initializing dictionary
test_dict = {'one':'value 1','two':'value 2','three':'value 3'}
def get_next_key(dic, current_key):
""" get the next key of a dictionary.
Parameters
----------
dic: dict
current_key: string
Return
------
next_key: string, represent the next key in dictionary.
or
False If the value passed in current_key can not be found in the dictionary keys,
or it is last key in the dictionary
"""
l=list(dic) # convert the dict keys to a list
try:
next_key=l[l.index(current_key) + 1] # using index method to get next key
except (ValueError, IndexError):
return False
return next_key
get_next_key(test_dict, 'two')
'three'
get_next_key(test_dict, 'three')
False
get_next_key(test_dict, 'one')
'two'
get_next_key(test_dict, 'NOT EXISTS')
False

TypeError: 'dict_items' object is not subscriptable on running if statement to shortlist items

I am using a function below to run the apriori algorithm and calculate support, confidence for all itemsets. The function uses a dictionary object to store all values of items and their corresponding support, confidence.
After running the if statement to select items having minimum support value of 0.15 and confidence of 0.6, I am getting an error below that dict_items object is not subscriptable.
for key, value in largeSet.items()[1:]:
TypeError: 'dict_items' object is not subscriptable
def runApriori(data_iter, minSupport, minConfidence):
"""
run the apriori algorithm. data_iter is a record iterator
Return both:
- items (tuple, support)
- rules ((pretuple, posttuple), confidence)
"""
itemSet, transactionList = getItemSetTransactionList(data_iter)
freqSet = defaultdict(int)
largeSet = dict()
# Global dictionary which stores (key=n-itemSets,value=support)
# which satisfy minSupport
assocRules = dict()
# Dictionary which stores Association Rules
oneCSet = returnItemsWithMinSupport(itemSet,
transactionList,
minSupport,
freqSet)
currentLSet = oneCSet
k = 2
while(currentLSet != set([])):
largeSet[k-1] = currentLSet
currentLSet = joinSet(currentLSet, k)
currentCSet = returnItemsWithMinSupport(currentLSet,
transactionList,
minSupport,
freqSet)
currentLSet = currentCSet
k = k + 1
def getSupport(item):
"""local function which Returns the support of an item"""
return float(freqSet[item])/len(transactionList)
toRetItems = []
for key, value in largeSet.items():
toRetItems.extend([(tuple(item), getSupport(item))
for item in value])
toRetRules = []
for key, value in largeSet.items()[1:]:
for item in value:
_subsets = map(frozenset, [x for x in subsets(item)])
for element in _subsets:
remain = item.difference(element)
if len(remain) > 0:
confidence = getSupport(item)/getSupport(element)
if confidence >= minConfidence:
toRetRules.append(((tuple(element), tuple(remain)),
confidence))
return toRetItems, toRetRules
if __name__ == "__main__":
inFile = ''
minSupport = 0.15
minConfidence = 0.6
items, rules = runApriori(inFile, minSupport, minConfidence)
printResults(items, rules)
Prior to CPython 3.6 (and 3.7 for any Python interpreter), dicts have no reliable ordering, so assuming the first item is the one you want to skip is a bad idea.
That said, if you're on 3.6+, and you know you want to skip the first element, you can use itertools.islice to do this safely, changing:
for key, value in largeSet.items()[1:]:
to:
# At top of file
from itertools import islice
for key, value in islice(largeSet.items(), 1, None):
You're not supposed to be relying on dictionaries having a particular order, so python doesn't let you skip the "first" item in a dictionary, since what is "first" depends on there being a particular order. You can cast it as a list: for key, value in list(largeSet.items())[1:], but that would rely on the dictionary order being what you expect it would be. Better would to just do for key, value in largeSet.items()), then check within the loop whether it's the item you don't want to operate on, and continue if it is. Or use pandas series.

What is the best way to append lists inside a dict?

I am trying to build a list that has 1 key to many values. The best way I can think to do this is by pointing a key value to a list. However, I am having trouble building the lists inside the dict.
num_items = len(decoded_data['data']['arrivalsAndDepartures'])
buses = list()
busdict = dict()
val = list()
for i in range(num_items):
decoded_data['data']['arrivalsAndDepartures']
bus = decoded_data['data']['arrivalsAndDepartures'][i]['routeId']
buses.append(bus)
try:
busdict[bus]
except KeyError:
busdict[bus] = [i]
print("except "+ bus , str(i))
else:
val = busdict[bus]
busdict[bus] = [val].append(i)
print("else "+ bus ,val, str(i))
This gives me weird results.
$ python test.py
except 40_590 0
except 40_554 1
except 40_592 2
else 40_590 [0] 3
except 1_122 4
except 40_577 5
else 40_590 None 6
From the above test result, the third time it hits the key '40_590' the value is cleared.
busdict[bus] = [val].append(i)
list.append is an inplace operation and returns None. So, you are clearing the previously stored list in it. You could fix it like this
busdict[bus].append(i)
But the best way to solve this problem is by using dict.setdefault function (which assigns and returns the default value if the specified key is not found), like this
busdict.setdefault(bus, []).append(i)
But the best way to solve this problem would be to use collections.defaultdict, like this
from collections import defaultdict
busdict = defaultdict(list)
...
...
busdict[bus].append(i)
list.append() does not return a value. Use it like this:
else:
val = busdict[bus].append(i)
print("else "+ bus ,val, str(i))
By the way: use four spaces for indents!

Categories