Write a function named count_letters that takes as a parameter a string and returns a dictionary that tabulates how many of each letter is in that string. The string can contain characters other than letters, but only the letters should be counted. The string could even be the empty string. Lower-case and upper-case versions of a letter should be part of the same count. The keys of the dictionary should be the upper-case letters. If a letter does not appear in the string, then it would not get added to the dictionary. For example, if the string is
"AaBb"
then the dictionary that is returned should contain these key-value pairs:
{'A': 2, 'B': 2}
def count_letters(string):
"""counts all the letters in a given string"""
your_dict = dict()
for x in string:
x = x.upper() # makes lowercase upper
if x not in your_dict:
your_dict[x]= 1
else:
your_dict[x] += 1
return your_dict
I am getting the following error when I go to upload:
Test Failed: {'Q': 1, 'U': 3, 'I': 3, 'S': 6, ' ': 3, 'C[48 chars]': 1} != {'S': 6, 'U': 3, 'I': 3, 'T': 3, 'O': 3, 'C[32 chars]': 1}
+ {'C': 2, 'D': 2, 'E': 2, 'I': 3, 'O': 3, 'P': 1, 'Q': 1, 'S': 6, 'T': 3, 'U': 3}
- {' ': 3,
- '?': 1,
- 'C': 2,
- 'D': 2,
- 'E': 2,
- 'I': 3,
- 'O': 3,
- 'P': 1,
- 'Q': 1,
- 'S': 6,
- 'T': 3,
- 'U': 3}
Try something like this. Feel free to adjust it to your requirements:
import collections
def count_letters(string):
return collections.Counter(string.upper())
print(count_letters('Google'))
Output: Counter({'G': 2, 'O': 2, 'L': 1, 'E': 1})
For documentation of the Counter dict subclass in collections module, check this.
Update without using collections module:
def count_letters(string):
your_dict={}
for i in string.upper():
if i in your_dict:
your_dict[i] += 1
else:
your_dict[i] = 1
return your_dict
Output: {'G': 2, 'O': 2, 'L': 1, 'E': 1}
This solution does use collections, but unlike with Counter we aren’t getting the entire solution from a single library function. I hope it’s permitted, and if it isn’t, that it will at least be informative in some way.
import collections as colls
def count_letters(str_in):
str_folded = str_in.casefold()
counts = colls.defaultdict(int)
for curr_char in str_folded:
counts[curr_char] += 1
return counts
defaultdict is extremely practical. As the name indicates, when we try to index a dictionary with a key that doesn’t exist, it creates a default value for that key and carries out our original operation. In this case, since we declare that our defaultdict will use integers for its keys, the default value is 0.
str.casefold() is a method designed specifically for the complex problem that is case-insensitive comparison. While it is unlikely to make a difference here, it’s a good function to know.
Let me know if you have any questions :)
Without using collections, here is a solution:
def count_letters(string):
string = string.upper()
counts = {}
for a in set(string):
counts[a] = string.count(a)
return counts
This function iterates over set(string), which is equal to all the letters used in your word, without duplicates, and in uppercase. Then it counts how many times each letter appears in your string, and adds it to your counts dictionary.
I hope this answers your question. :)
Related
I am trying to write a function which will count the number of characters present in an input string and store as key-value in a dictionary.The code is partially working i.e it is also counting the whitespaces present in between 2 words.How do I avoid counting the whitespaces?
#Store Characters of a string in a Dictionary
def char_dict(string):
char_dic = {}
for i in string:
if i in char_dic:
char_dic[i]+= 1
else:
char_dic[i]= 1
return char_dic
print(char_dict('My name is Rajib'))
You could just continue if the character is a white space:
def char_dict(string):
char_dic = {}
for i in string:
if ' ' == i:
continue
if i in char_dic:
char_dic[i] += 1
else:
char_dic[i]= 1
return char_dic
print(char_dict('My name is Rajib')) # {'j': 1, 'm': 1, 'M': 1, 'i': 2, 'b': 1, 'e': 1, 'a': 2, 'y': 1, 'R': 1, 'n': 1, 's': 1}
A cleaner solution would be:
from collections import defaultdict
def countNonSpaceChars(string):
charDic = defaultdict(lambda: 0)
for char in string:
if char.isspace():
continue
charDic[char] += 1
return dict(charDic)
print(countNonSpaceChars('My name is Rajib')) # {'i': 2, 'a': 2, 'R': 1, 'y': 1, 'M': 1, 'm': 1, 'e': 1, 'n': 1, 'j': 1, 's': 1, 'b': 1}
You can delete space -> string = string.replace (" ","")
def char_dict(string):
char_dic = {}
string=string.replace(" ","")
for i in string:
if i in char_dic:
char_dic[i]+= 1
else:
char_dic[i]= 1
return char_dic
print(char_dict('My name is Rajib'))
To simplify things for you, there's a library called collections that has a Counter function that will produce a dictionary of values and their occurrences in a string. Then, I would simply remove the whitespace key from the dictionary if it is present using the del keyword.
from collections import Counter
def char_dict(string):
text = 'My name is Rajib'
c = Counter(text)
if ' ' in c: del c[' ']
print(char_dict('My name is Rajib'))
This method is very readable and doesn't require too much reinventing.
I was wondering if anyone could help me out.
How do I get this code to record ONLY the frequency of letters in a text file into a dictionary (does NOT count spaces, line, numbers, etc)?
Additionally how do I divide each letter by the total letters to report the percent frequency of each letter in the file?
This is what I have currently:
def linguisticCalc():
"""
Asks user to input a VALID filename. File must be a text file. IF valid, returns the frequency of ONLY letters in file.
"""
filename = input("Please type your VALID filename")
if os.path.exists(filename) == True:
with open(filename, 'r') as f:
f_content = f.read()
freq = {}
for i in f_content:
if i in freq:
freq[i] += 1
else:
freq[i] = 1
print(str(freq))
else:
print("This filename is NOT valid. Use the getValidFilename function to test inputs.")
Something that might help you determine whether the character in question is a letter, is this:
import string
# code here
if character in string.ascii_letters:
# code here
Check out collections.Counter()
You can use it to Count every letter in a string:
Counter('Articles containing potentially dated statements from 2011')
It gives this output, which is useful for counting characters in a string:
Counter({'A': 1,
'r': 2,
't': 8,
'i': 4,
'c': 2,
'l': 3,
'e': 5,
's': 3,
' ': 6,
'o': 3,
'n': 5,
'a': 4,
'g': 1,
'p': 1,
'y': 1,
'd': 2,
'm': 2,
'f': 1,
'2': 1,
'0': 1,
'1': 2})
This question already has answers here:
Counting each letter's frequency in a string
(2 answers)
Closed 4 years ago.
How do I create a function that will let me input a word, and it will execute to create a dictionary that counts individual letters in the code. I would want it to display as a dictionary, for example, by inputting 'hello' it will display {'e': 1, 'h': 1, 'l': 2, 'o': 1}
I AM ALSO required to have 2 arguments in the function, one for the string and one for the dictionary. THIS IS DIFFERENT to the "Counting each letter's frequency in a string" question.
For example, I think I would have to start as,
d = {}
def count(text, d ={}):
count = 0
for l in text:
if l in d:
count +=1
else:
d.append(l)
return count
But this is incorrect? Also Would i need to set a default value to text, by writing text ="" in case the user does not actually enter any word?
Furthermore, if there were existing values already in the dictionary, I want it to add to that existing list. How would this be achieved?
Also if there were already existing words in the dictionary, then how would you add onto that list, e.g. dct = {'e': 1, 'h': 1, 'l': 2, 'o': 1} and now i run in terminal >>> count_letters('hello', dct) the result would be {'e': 2, 'h': 2, 'l': 4, 'o': 2}
If you can use Pandas, you can use value_counts():
import pandas as pd
word = "hello"
letters = [letter for letter in word]
pd.Series(letters).value_counts().to_dict()
Output:
{'e': 1, 'h': 1, 'l': 2, 'o': 1}
Otherwise, use dict and list comprehensions:
letter_ct = {letter:0 for letter in word}
for letter in word:
letter_ct[letter] += 1
letter_ct
You can use pythons defaultdict
from collections import defaultdict
def word_counter(word):
word_dict = defaultdict(int)
for letter in word:
word_dict[letter] += 1
return(word_dict)
print(word_counter('hello'))
Output:
defaultdict(<class 'int'>, {'h': 1, 'e': 1, 'l': 2, 'o': 1})
def count_freqs(string, dictionary={}):
for letter in string:
if letter not in dictionary:
dictionary[letter] = 1
else:
dictionary[letter] += 1
return dictionary
I've been tasked with creating a dictionary whose keys are elements found in a string and whose values count the number of occurrences per value.
Ex.
"abracadabra" → {'r': 2, 'd': 1, 'c': 1, 'b': 2, 'a': 5}
I have the for-loop logic behind it here:
xs = "hshhsf"
xsUnique = "".join(set(xs))
occurrences = []
freq = []
counter = 0
for i in range(len(xsUnique)):
for x in range(len(xs)):
if xsUnique[i] == xs[x]:
occurrences.append(xs[x])
counter += 1
freq.append(counter)
freq.append(xsUnique[i])
counter = 0
This does exactly what I want it to do, except with lists instead of dictionaries. How can I make it so counter becomes a value, and xsUnique[i] becomes a key in a new dictionary?
The easiest way is to use a Counter:
>>> from collections import Counter
>>> Counter("abracadabra")
Counter({'a': 5, 'r': 2, 'b': 2, 'c': 1, 'd': 1})
If you can't use a Python library, you can use dict.get with a default value of 0 to make your own counter:
s="abracadabra"
count={}
for c in s:
count[c] = count.get(c, 0)+1
>>> count
{'a': 5, 'r': 2, 'b': 2, 'c': 1, 'd': 1}
Or, you can use dict.fromkeys() to set all the values in a counter to zero and then use that:
>>> counter={}.fromkeys(s, 0)
>>> counter
{'a': 0, 'r': 0, 'b': 0, 'c': 0, 'd': 0}
>>> for c in s:
... counter[c]+=1
...
>>> counter
{'a': 5, 'r': 2, 'b': 2, 'c': 1, 'd': 1}
If you truly want the least Pythonic, i.e., what you might do in C, you would maybe do:
create a list for all possible ascii values set to 0
loop over the string and count characters that are present
Print non zero values
Example:
ascii_counts=[0]*255
s="abracadabra"
for c in s:
ascii_counts[ord(c)]+=1
for i, e in enumerate(ascii_counts):
if e:
print chr(i), e
Prints:
a 5
b 2
c 1
d 1
r 2
That does not scale to use with Unicode, however, since you would need more than 1 million list entries...
You can use zip function to convert your list to dictionary :
>>> dict(zip(freq[1::2],freq[0::2]))
{'h': 3, 's': 2, 'f': 1}
But as more pythonic and pretty optimized way I suggest to use collections.Counter
>>> from collections import Counter
>>> Counter("hshhsf")
Counter({'h': 3, 's': 2, 'f': 1})
And as you said you don't want to import any module you can use a dictionary using dict.setdefault method and a simple loop:
>>> d={}
>>> for i in xs:
... d[i]=d.setdefault(i,0)+1
...
>>> d
{'h': 3, 's': 2, 'f': 1}
I'm guessing theres a learning reason as to why your using two forloops?
Anyway heres a few different solutions:
# Method 1
xs = 'hshhsf'
xsUnique = ''.join(set(xs))
freq1 = {}
for i in range(len(xsUnique)):
for x in range(len(xs)):
if xsUnique[i] == xs[x]:
if xs[x] in freq1:
freq1[xs[x]] += 1
else:
freq1[xs[x]] = 1 # Introduce a new key, value pair
# Method 2
# Or use a defaultdict that auto initialize new values in a dictionary
# https://docs.python.org/2/library/collections.html#collections.defaultdict
from collections import defaultdict
freq2 = defaultdict(int) # new values initialize to 0
for i in range(len(xsUnique)):
for x in range(len(xs)):
if xsUnique[i] == xs[x]:
# no need to check if xs[x] is in the dict because
# defaultdict(int) will set any new key to zero, then
# preforms it's operation.
freq2[xs[x]] += 1
# I don't understand why your using 2 forloops though
# Method 3
string = 'hshhsf' # the variable name `xs` confuses me, sorry
freq3 = defaultdict(int)
for char in string:
freq3[char] += 1
# Method 4
freq4 = {}
for char in string:
if char in freq4:
freq4[char] += 1
else:
freq4[char] = 1
print 'freq1: %r\n' % freq1
print 'freq2: %r\n' % freq2
print 'freq3: %r\n' % freq3
print 'freq4: %r\n' % freq4
print '\nDo all the dictionaries equal each other as they stand?'
print 'Answer: %r\n\n' % (freq1 == freq2 and freq1 == freq3 and freq1 == freq4)
# convert the defaultdict's to a dict for consistency
freq2 = dict(freq2)
freq3 = dict(freq3)
print 'freq1: %r' % freq2
print 'freq2: %r' % freq2
print 'freq3: %r' % freq3
print 'freq4: %r' % freq4
Output
freq1: {'h': 3, 's': 2, 'f': 1}
freq2: defaultdict(<type 'int'>, {'h': 3, 's': 2, 'f': 1})
freq3: defaultdict(<type 'int'>, {'h': 3, 's': 2, 'f': 1})
freq4: {'h': 3, 's': 2, 'f': 1}
Do all the dictionaries equal each other as they stand?
Answer: True
freq1: {'h': 3, 's': 2, 'f': 1}
freq2: {'h': 3, 's': 2, 'f': 1}
freq3: {'h': 3, 's': 2, 'f': 1}
freq4: {'h': 3, 's': 2, 'f': 1}
[Finished in 0.1s]
Or like dawg stated, use Counter from the collections standard library
counter docs
https://docs.python.org/2/library/collections.html#collections.Counter
defaultdict docs
https://docs.python.org/2/library/collections.html#collections.defaultdict
collections library docs
https://docs.python.org/2/library/collections.html
Trying to write function that returns True if word in list and only made up of letters in hand. I am fine on checking if word in list, but cannot figure out how to iterate through to check the second part. The below is incorrectly returning True:
word = 'chayote'
hand = {'a': 1, 'c': 2, 'u': 2, 't': 2, 'y': 1, 'h': 1, 'z': 1, 'o': 2}
list = ['peach', 'chayote']
def ValidWord(word, hand, list):
if word in list:
for i in word:
if i in hand:
return True
return False
else:
return False
ValidWord(word, hand, list)
The simplest way to solve this would be to use collections.Counter, like this
from collections import Counter
def is_valid_word(word, hand, list):
if word in my_list:
return len(Counter(word) - Counter(hand)) == 0
return False
my_list = ['peach', 'chayote']
hand = {'a': 1, 'c': 2, 'u': 2, 't': 2, 'y': 1, 'h': 1, 'z': 1, 'o': 2}
print is_valid_word("chayote", hand, my_list)
# False
print is_valid_word("peach", hand, my_list)
# False
I think you can use all to do this, might be more concise:
if all(i in hand for i in words):
return True
If the count matters, see #thefourtheye's answer.
You can change the returns inside for loop:
word = 'chayote'
word2 = 'peach'
hand = {'a': 1, 'c': 2, 'u': 2, 't': 2, 'y': 1, 'h': 1, 'z': 1, 'o': 2, 'e': 2} # I added 'e' so chayote is true and peach is false
list = ['peach', 'chayote']
def ValidWord(word, hand, list):
if word in list:
for i in word:
if i not in hand:
return False
return True
else:
return False
print(ValidWord(word, hand, list))
print(ValidWord(word2, hand, list))
If count matters expand Gnijuohz' solution:
def ValidWord(word,hand,list):
return word in list and all(i in hand for i in word) and all(hand[key]>=word.count(key) for key in hand.keys())
This will return False if a letter appears more often in word than the value hand[letter].
If you want to have at least the amount of each letter in the word specified by the hand dictionary, just change it to hand[key]<=word.count(key).
As far as I see the last way would be equivalent to the solution by thefourtheye using Counter