I am writing a python program to find character sequence in a word. But the program is giving the unexpected result.
I have found a similar type program that works perfectly.
To me I think the two program is quite similar but dont know why one of them does not work
The program that is not working:
# Display the character sequence in a word
dict={}
string=input("Enter the string:").strip().lower()
for letter in string:
if letter !=dict.keys():
dict[letter]=1
else:
dict[letter]=dict[letter]+1
print(dict)
The program that is working:
def char_frequency(str1):
dict = {}
for n in str1:
keys = dict.keys()
if n in keys:
dict[n] += 1
else:
dict[n] = 1
return dict
print(char_frequency('google.com'))
The output for the first program is giving:
Enter the string:google.com
{'g': 1, 'c': 1, 'm': 1, 'o': 1, 'l': 1, '.': 1, 'e': 1}
The output for the second program is:
{'c': 1, 'e': 1, 'o': 3, 'g': 2, '.': 1, 'm': 1, 'l': 1}
The above is the correct output.
Now the questions in my mind.
i. Why the first program is not working correctly?
ii. Is the ideology of these two programs are different?
Actually, there's a little mistake is in the if statement you have used. Just have a look at the below modified program.
Note: Also make sure not to use pre-defined data type names like dict as variable names. I have changed that to d here.
>>> d = {}
>>>
>>> string=input("Enter the string:").strip().lower()
Enter the string:google.com
>>>
>>> for letter in string:
... if letter not in d.keys():
... d[letter] = 1
... else:
... d[letter] = d[letter] + 1
...
>>> print(d)
{'g': 2, 'o': 3, 'l': 1, 'e': 1, '.': 1, 'c': 1, 'm': 1}
>>>
You can have also have a look at the below statements executed on the terminal.
Comparing a key with d.keys() will always return False as key is a string here and d.keys() will always be an object of type dict_keys (Python3) and a list (Python2).
>>> d = {"k1": "v1", "k3": "v2", "k4": "Rishi"}
>>>
>>> d.keys()
dict_keys(['k1', 'k3', 'k4'])
>>>
>>> "k1" in d
True
>>>
>>> not "k1" in d
False
>>>
>>> "k1" == d.keys()
False
>>>
>>> "k1" not in d
False
>>>
Answers of your 2 questions:
Because the statement letter != dict.keys() is always True so no increment in key counts. Just change it to letter not in dict.keys(). And it is better to use d in place of dict so that the statement will look like letter not in d.keys().
Logic of both the programs are same i.e. iterating over the dictionary, checking for an existence of key in dictionary. If it does not exist, create a new key with count 1 else increment the related count by 1.
Thank you v. much.
This line is nonsensical:
if letter !=dict.keys():
letter is a length one str, while dict.keys() returns a key view object, which is guaranteed to never be equal to a str of any kind. Your if check is always false. The correct logic would be:
if letter not in dict:
(you could add .keys() if you really want to, but it's wasteful and pointless; membership testing on a dict is checking its keys implicitly).
Side-note: You're going to confuse the crap out of yourself by naming a variable dict, because you're name-shadowing the dict constructor; if you ever need to use it, it won't be available in that scope. Don't shadow built-in names if at all possible.
Related
In this example I'm taking letters from a set and append them to a dictionary where the letter becomes the key and the literal 1 becomes the value to each pair.
def base_dict_from_set(s):
return reduce(lambda d,e : addvalue(1, e, d), s, dict())
def addvalue(value, key, d):
d[key] = value
return d
>>> base_dict_from_set(set("Hello World!".lower()))
{'o': 1, '!': 1, 'l': 1, 'd': 1, 'w': 1, ' ': 1, 'r': 1, 'e': 1, 'h': 1}
I was wondering whether I could somehow be rid of the 'addvalue' helper function and add the element and reference the modified dictionary within the lambda function itself.
The routine within addvalue itself seams very simple to me, so I would prefer something that looks like this:
def base_dict_from_set(s):
reutrn reduce(lambda d,e : d[e] = 1, s, dict())
I don't have a lot of experience in python and I come from a functional programming perspective. My goal is to understand pythons functional capabilities but I am too unexperienced to properly phrase and google what I am looking for.
What you are trying to do is why dict.fromkeys exists: create a dict that maps each key to the same constant value.
>>> dict.fromkeys("Hello World!".lower(), 1)
{'h': 1, 'e': 1, 'l': 1, 'o': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1, '!': 1}
There's no need to convert the string to a set first, since any duplicates will just be overwritten by the following occurrences.
(If the constant value is mutable, you should use the dict comprehension to ensure that each key gets its own mutable value, rather than every key sharing a reference to the same mutable value.)
You can use a dict comprehension for the same result:
{l: 1 for l in set("Hello World!".lower())}
To answer exactly the question asked, yes you can get rid of the addvalue by replacing addvalue(1, e, d) with {**d, e:1}.
Nevertheless, your code is still faulty. It is not counting the occurrences, but creates a dict of key: 1 for every letter in the string and it should create a dict of key: number_of_occurences to achieve this you should replace addvalue(1, e, d) with {**d, e: 1 + (d[e] if e in d else 0)} and not convert the string to set as it eliminates duplicates
I'm a bit surprised that you tried to use reduce when your goal is to transform each item in an input collection (the letters in a string) to an output collection (a key/value pair where the key is the letter and the value is a constant number), independently of each other.
In my view, reduce is for when an operation needs to be done to items in a sequence and taking all previous items into account (for instance, when calculating a sum of values).
So in a functional style, using map here would be more appropriate than reduce, in my opinion. Python supports this:
def quant_dict_from_set(s):
return dict(map(lambda c: (c, 1), s.lower()))
Where map converts the string to key/value pairs and the dict constructor collects these pairs in a dictionary, while eliminating duplicate keys at the same time.
But more idiomatic approaches would be to use a dictionary comprehension or the dict.fromkeys constructor.
Hacky and hard to read, but closest to the lambda you were trying to write, and hopefully educational:
>>> f = lambda d, e: d.__setitem__(e, 1) or d
>>> d = {}
>>> output = f(d, 42)
>>> output
{42: 1}
>>> output is d
True
Using __setitem__ avoids the = assignment.
__setitem__ returns None, so the expression d.__setitem__(e, 1) or d always evaluates to d, which is returned by the lambda.
You can use collections.Counter, a subclass of dict specifically for counting occurrences of elements.
>>> import collections
>>> collections.Counter('Hello, World!'.lower())
Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ',': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1, '!': 1})
>>> collections.Counter(set('Hello, World!'.lower()))
Counter({'w': 1, 'l': 1, 'r': 1, ',': 1, 'h': 1, 'd': 1, 'o': 1, 'e': 1, ' ': 1, '!': 1})
Note that Counter is appropriate if you want to count the elements, of if you want to initiate the values to the constant 1. If you want to initiate the values to another constant, then Counter will not be the solution and you should use a dictionary comprehension or the dict.fromkeys constructor.
I want to write a code in Python, which assigns a number to every alphabetical character, like so: a=0, b=1, c=2, ..., y=24, z=25. I personally don't prefer setting up conditions for every single alphabet, and don't want my code look over engineered. I'd like to know the ways I can do this the shortest (meaning the shortest lines of code), fastest and easiest.
(What's on my mind is to create a dictionary for this purpose, but I wonder if there's a neater and better way).
Any suggestions and tips are in advance appreciated.
You definitely want a dictionary for this, not to declare each as a variable. A simple way is to use a dictionary comprehension with string.ascii_lowercase as:
from string import ascii_lowercase
{v:k for k,v in enumerate(ascii_lowercase)}
# {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 5...
Here's my two cents, for loop will do the work:
d = {} #empty dictionary
alpha = 'abcdefghijklmnopqrstuvwxyz'
for i in range(26):
d[alpha[i]] = i #assigns the key value as alphabets and corresponding index value from alpha string as the value for the key
print(d) #instant verification that the dictionary has been created properly
One-liner with map and enumerate:
# given
foo = 'abcxyz'
dict(enumerate(foo))
# returns: {0: 'a', 1: 'b', 2: 'c', 3: 'x', 4: 'y', 5: 'z'}
If you needed it with the characters as the dictionary keys, what comes into my mind is either a dict comprehension...
{letter:num for (num,letter) in enumerate(foo) }
# returns {'a': 0, 'b': 1, 'c': 2, 'z': 3, 'y': 4, 'x': 5}
... or a lambda...
dict( map(lambda x: (x[1],x[0]), enumerate(foo)) )
# returns {'a': 0, 'b': 1, 'c': 2, 'z': 3, 'y': 4, 'x': 5}
I feel dict comprehension is much more readable than map+lambda+enumerate.
There are already numbers associated with characters. You can use these code points with ord().
A short (in terms of lines) solution would be:
num_of = lambda s: ord(s) - 97
A normal function would be easier to read:
def num_of(s):
return ord(s) - 97
Usage:
num_of("a") # 0
num_of("z") # 25
If it must be a dictionary you can create it without imports like that:
{chr(n):n-97 for n in range(ord("a"), ord("z")+1)}
I'm so stuck on this task. I have a task where I need to write a program in python 2.7 which prompts a user to input a string and then the program needs to return the number of times the letters in that string occur. for example the word "google.com" must return 'o': 3, 'g': 2, '.': 1, 'e': 1, 'l': 1, 'm': 1, 'c': 1
I know i need to use the list() function but all i have so far is:
string = raw_input("Enter a string: ")
newString = list(string)
and then i get stuck from there because I don't know how to make the program count the number of times the letters occur. I know there must be a for loop in the syntax but I'm not sure how I'm going to use it in this case.
NB: We haven't been introduced to dictionaries or imports yet so please keep it as simple as possible. Basically the most round about method will work best.
You can handle this problem directly with the help of count function.
You can start with an empty dictonary and add each character of the entered string and its count to the dictionary.
This can be done like this..!
string = raw_input("Enter a string: ")
count_dict = {}
for x in string:
count_dict[x] = string.count(x)
print count_dict
#input : google.com
# output : {'c': 1, 'e': 1, 'g': 2, 'm': 1, 'l': 1, 'o': 3, '.': 1}
Update:
Since you haven't been introduced to dictionary and imports, you can use the below solution.
for i in set(string):
print("'{}'".format(i), string.count(i), end=",")
Use Counter:
from collections import Counter
string = "google.com"
print(Counter(string))
Other way, create a dictionary and add chars looping through your string.
dicta = {}
for i in string:
if i not in dicta:
dicta[i] = 1
else:
dicta[i] += 1
print(dicta)
This question already has answers here:
Why dict.get(key) instead of dict[key]?
(14 answers)
Closed 4 years ago.
sentence = "The quick brown fox jumped over the lazy dog."
characters = {}
for character in sentence:
characters[character] = characters.get(character, 0) + 1
print(characters)
I don't understand what characters.get(character, 0) + 1 is doing, rest all seems pretty straightforward.
The get method of a dict (like for example characters) works just like indexing the dict, except that, if the key is missing, instead of raising a KeyError it returns the default value (if you call .get with just one argument, the key, the default value is None).
So an equivalent Python function (where calling myget(d, k, v) is just like d.get(k, v) might be:
def myget(d, k, v=None):
try: return d[k]
except KeyError: return v
The sample code in your question is clearly trying to count the number of occurrences of each character: if it already has a count for a given character, get returns it (so it's just incremented by one), else get returns 0 (so the incrementing correctly gives 1 at a character's first occurrence in the string).
To understand what is going on, let's take one letter(repeated more than once) in the sentence string and follow what happens when it goes through the loop.
Remember that we start off with an empty characters dictionary
characters = {}
I will pick the letter 'e'. Let's pass the character 'e' (found in the word The) for the first time through the loop. I will assume it's the first character to go through the loop and I'll substitute the variables with their values:
for 'e' in "The quick brown fox jumped over the lazy dog.":
{}['e'] = {}.get('e', 0) + 1
characters.get('e', 0) tells python to look for the key 'e' in the dictionary. If it's not found it returns 0. Since this is the first time 'e' is passed through the loop, the character 'e' is not found in the dictionary yet, so the get method returns 0. This 0 value is then added to the 1 (present in the characters[character] = characters.get(character,0) + 1 equation).
After completion of the first loop using the 'e' character, we now have an entry in the dictionary like this: {'e': 1}
The dictionary is now:
characters = {'e': 1}
Now, let's pass the second 'e' (found in the word jumped) through the same loop. I'll assume it's the second character to go through the loop and I'll update the variables with their new values:
for 'e' in "The quick brown fox jumped over the lazy dog.":
{'e': 1}['e'] = {'e': 1}.get('e', 0) + 1
Here the get method finds a key entry for 'e' and finds its value which is 1.
We add this to the other 1 in characters.get(character, 0) + 1 and get 2 as result.
When we apply this in the characters[character] = characters.get(character, 0) + 1 equation:
characters['e'] = 2
It should be clear that the last equation assigns a new value 2 to the already present 'e' key.
Therefore the dictionary is now:
characters = {'e': 2}
Start here http://docs.python.org/tutorial/datastructures.html#dictionaries
Then here http://docs.python.org/library/stdtypes.html#mapping-types-dict
Then here http://docs.python.org/library/stdtypes.html#dict.get
characters.get( key, default )
key is a character
default is 0
If the character is in the dictionary, characters, you get the dictionary object.
If not, you get 0.
Syntax:
get(key[, default])
Return the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError.
If d is a dictionary, then d.get(k, v) means, give me the value of k in d, unless k isn't there, in which case give me v. It's being used here to get the current count of the character, which should start at 0 if the character hasn't been encountered before.
I see this is a fairly old question, but this looks like one of those times when something's been written without knowledge of a language feature. The collections library exists to fulfill these purposes.
from collections import Counter
letter_counter = Counter()
for letter in 'The quick brown fox jumps over the lazy dog':
letter_counter[letter] += 1
>>> letter_counter
Counter({' ': 8, 'o': 4, 'e': 3, 'h': 2, 'r': 2, 'u': 2, 'T': 1, 'a': 1, 'c': 1, 'b': 1, 'd': 1, 'g': 1, 'f': 1, 'i': 1, 'k': 1, 'j': 1, 'm': 1, 'l': 1, 'n': 1, 'q': 1, 'p': 1, 's': 1, 't': 1, 'w': 1, 'v': 1, 'y': 1, 'x': 1, 'z': 1})
In this example the spaces are being counted, obviously, but whether or not you want those filtered is up to you.
As for the dict.get(a_key, default_value), there have been several answers to this particular question -- this method returns the value of the key, or the default_value you supply. The first argument is the key you're looking for, the second argument is the default for when that key is not present.
I have a problem concerning a comparison between a char key in a dict and a char within a list.
The Task is to read a text and count all beginning letters.
I have a list with chars:
bchars = ('i','g','h','n','h')
and a dict with the alphabet and frequency default to zero:
d = dict(dict())
for i in range(97,123):
d[i-97]={chr(i):0}
no i want to check like the following:
for i in range(len(bchars)):
for j in range(len(d)):
if(bchars[i] in d[j]):
d[j][chr(i+97)] +=1
else:
d[j][chr(i+97)] +=0
so if the char in the list is a key at the certain position then += 1 else += zero
I thought by using a if/else statement I can bypass the KeyError.
Is there any more elegant solution for that?
The specific problem is that you check whether bchars[i] is in d[j], but then the key you actually use is chr(i+97).
chr(i+97) is the index of the ith character in bchars, but mapped to ASCII characters starting from 'a'. Why would you want to use this as your key?
I think you really want to do:
for i in range(len(bchars)):
for j in range(len(d)):
if(bchars[i] in d[j]):
d[j][bchars[i]] += 1
else:
d[j][bchars[i]] = 1
Note that you can't use += in the else; remember how you literally just checked whether the key was there and decided it wasn't?
More broadly, though, your code doesn't make sense - it is overcomplicated and does not use the real power of Python's dictionaries. d looks like:
{0: {'a': 0}, 1: {'b': 0}, 2: {'c': 0}, ...}
It would be much more sensible to build a dictionary mapping character directly to count:
{'a': 0, 'b': 0, 'c': 0, ...}
then you can simply do:
for char in bchars:
if char in d:
d[char] += 1
Python even comes with a class just for doing this sort of thing.
The nested dictionary doesn't seem necessary:
d = [0] * 26
for c in bchars:
d[ord(c)-97] += 1
You might also want to look at the Counter class in the collections module.
from collections import Counter
bchars = ('i','g','h','n','h')
counts = Counter(bchars)
print(counts)
print(counts['h'])
prints
Counter({'h': 2, 'i': 1, 'g': 1, 'n': 1})
2