Why KeyError raises even the respective key exists? - python-3.x

def countLetter(string):
dic = dict()
for char in string:
dic[char] = (1,dic[char]+1)[char in dic]
print(dic)
countLetter('aabcb')
Here, I'm trying to count the number of times each letter has occured, but the line 4 raises an error.
It raises an KeyError.

The problem is that this line:
dic[char] = (1,dic[char]+1)[char in dic]
is eagerly evaluating dic[char]+1 as part of constructing the tuple to index before you get around to testing if char in dic to select the element of the tuple. So it dies with a KeyError before your test has a chance to prevent the failing lookup. To make it lazy, you could do:
dic[char] = dic[char] + 1 if char in dic else 1
or you could just use a method designed for this to avoid the explicit test:
dic[char] = dic.get(char, 0) + 1
Though this particular pattern is made even simpler with collections.Counter:
import collections
def countLetter(string):
print(collections.Counter(string)) # print(dict(collections.Counter(string))) if it must look like a dict

Related

Index out of range in leetcode ide in code for finding the length of the longest substring without repeating characters

This below giving expected output in pycharm and the other side it's getting index out of range in line return length_of_substring[-1] in leetcode.
why it is getting such error?
class Solution:
def lengthOfLongestSubstring(self, string):
unique_list = []
length_of_substring = []
for i in string:
if i not in unique_list:
unique_list.append(i)
else:
length_of_substring.append(len(unique_list))
unique_list.clear()
unique_list.append(i)
length_of_substring.sort()
return length_of_substring[-1]
if __name__ == '__main__':
s = input()
obj = Solution()
result = Solution.lengthOfLongestSubstring(obj, s)
print(result)
First of all: when posting here you should clearly specify (i) the goal of your code and (ii) a self contained minimum example.
In your case it is very difficult to answer your question, because you do not make clear what your code is actually trying to achieve.
Regarding your error message:
Your code does not account for the fact that a string could also consist of only unique elements (e.g. "abcd"). In that case the else clause of your code is never reached and length_of_substring will remain empty. If you then call length_of_substring[-1] it raises an error message.

List Index Error - Combining list elements via index

'Original String = 1234 A 56 78 90 B'
def func_1(one_dict):
global ends
ends = []
for x in original_string:
if x in one_dict:
ends.append(one_dict[x])
return ends
The above returns:
['B', 'A']
My next function is supposed to then combine them into 1 string and get value from dictionary. I've tried this with/without the str in mult_ends with the same result.
def func_2(two_dict):
global mult_ends
mult_ends = str(ends[0] + ends[1])
for key in mult_ends:
if key in two_dict:
return two_dict[key]
The results confuse me since I use pretty identical processes in other functions with no issue.
IndexError: list index out of range
Why would the list index be out of range when there is clearly a 0 and 1? I've also added global ends to func_2 and I still received the same error.
*** RESTRUCTURED FUNCTIONS INTO 1 ***
def func_1(one_dict):
global ends
ends = []
for x in original_string:
if x in one_dict:
ends.append(one_dict[x])
mult_ends = ends[0] + ends[1]
for key in two_dict:
if key in mult_ends:
return ends_final_dict[key]
return None
Now, it actually does what I want it to do and returns the correct dictionary key in the event log:
A B
However, it does not return when I try to insert it back into my GUI for the user and it still throws the IndexError: list index out of range.

Is there a clean way to access the local iteration scope of a generator expression?

I am receiving a generator expression as an input argument to my function, and it looks like this:
(<some calculation> for item1 in list1) # single iterator case
(<some calculation> for item1 in list1 for item2 in list2) # multiple iterator case
The function is doing some internal stuff but in the end needs to return a dictionary that looks like this:
{item1: <calculated value>, ..} # single case
{(item1, item2): <calculated value>, ..} # multiple case
This works but I'd prefer to avoid messing around with what is obviously generator expression internals. Is there a clean way of making this work? I can imagine this could break in different versions of Python.
def to_dict(gen_expr):
d = {}
for x in gen_expr:
local_vars = gen_expr.gi_frame.f_locals
key = tuple(v for k, v in local_vars.items()
if k != ".0") # ".0" points to the iterator object
if len(key) == 1:
key = key[0]
d[key] = x
return d
EDIT:
This works in the IPython console but running the same piece of code in the Anaconda prompt crashes on f_locals, which then suddenly also contains all objects from the generator code block. Because these objects are not (necessarily) hashable, it raises a TypeError on d[key] = x. So my fears about (ab)using generator internals were quickly confirmed.

Calculating the occurrence of unknown values in a list

I very often face the following problem:
I have a list with unknown elements in it (but each element is of the same type, e.g.: str) and I want to count the occurrence of each element. Sometime I also want to do something with the occurrence values, so I usually store them in a dictionary.
My problem is, that I cannot "auto initialize" a dictionary with +=1, so I first I have to do a check, if the given element is still in the dictionary.
My usual go to solution:
dct = {}
for i in iterable:
if i in dct:
dct[i] += 1
else:
dct[i] = 1
Is there a simpler colution to this problem?
Yes! A defaultdict.
from collections import defaultdict
dct = defaultdict(int)
for i in iterable:
dict[i] += 1
You can auto-initialise with other types too:
Docs: https://docs.python.org/3.3/library/collections.html#collections.defaultdict
d = defaultdict(str)
d[i] += 'hello'
If you're just counting things, you could use a Counter instead:
from collections import Counter
c = Counter(iterable) # c is a subclass of dict

When I try to run my code, I seem to run with an IndexError

When I try to run my code, I seem to run with an IndexError.
def _init_trellis(self, observed, forward=True, init_func=identity):
trellis = [ [None for j in range(len(observed))]
for i in range(len(self.real_states) + 1) ]
if forward:
v = lambda s: self.transition(0, s) * self.emission(s, observed[1])
else:
v = lambda s: self.transition(s, self.end_state)
init_pos = 1 if forward else -1
for state in self.state_nums():
trellis[state][init_pos] = init_func( v(state) )
return trellis
ERROR:
v = lambda s: self.transition(0, s) * self.emission(s, observed[1]) IndexError: list index out of range
Add assertions to your code.
assert(len(observed) > 1)
will ensure that the array is long enough.
Update:
This happens when you try to access a list with an index, but the list does not have that many elements to show.
For example:
a_list = ['a', 'b', 'c']
print(a_list[0] # Prints a.
print(a_list[2] # Prints c.
print(a_list[3] # Gives IndexError.
'''Index of 3 means the 4th element of the list is being accessed.
Since the list only has 3 elements, it gives an index error.'''
In this case, observed[1] giving an index error means observed has only 1 element.
That is, len(observed) is 1.
Original Answer:
Based on the error, ensure that observed is an iterable with a minimum length of 2.

Resources