Populating a List - Python assigns index and gives error - python

I have a solution to count the number of occurrences of each letter in a string and return a dict.
def count_characters(in_str):
all_freq = {}
for i in in_str:
if i in all_freq:
all_freq[i] += 1
else:
all_freq[i] = 1
return all_freq
count_characters("Hello")
It works.
I am trying to understand how Python automatically assigns each letter as the key to the dict - its not explicitly assigned. I replace the null dictionary assignment with a list and expect to get just the frequency, without the letter.
def count_characters(in_str):
all_freq = []
for i in in_str:
if i in all_freq:
all_freq[i] += 1
else:
all_freq[i] = 1
return all_freq
count_characters("Hello")
I get an error.
TypeError: list indices must be integers or slices, not str
My question is:
How does each letter get automatically assigned as the key?
How can I return just the numbers as a list - without the letter?

How does each letter get automatically assigned as the key?
You are doing it explicitly in all_freq[i] = 1. Here, i contains a letter (though I think the variable could be named better — i typically stands for an idex of some sort, which this isn't).
How can I return just the numbers as a list - without the letter?
You could still build a dictionary and then return list(all_freq.values()). Though, if you do that, how would you know which letter each count corresponds to?
This is probably not relevant for your exercise, but the standard library already has a class for doing this sort of counting: collections.Counter.

List are indexing with integer, in your second exemple you use dictionary synthax with a list, that why python complain.
You can use count method
def count_characters(in_str):
all_freq = []
for i in in_str:
all_freq.append(in_str.count(i))
return all_freq
count_characters("Hello")
Edit : I agree with #NPE comment
You could still build a dictionary and then return list(all_freq.values()). Though, if you do that, how would you know which letter each count corresponds to?
This is probably not relevant for your exercise, but the standard library already has a class for doing this sort of counting: collections.Counter.

It's simple when we use built-in methods of dictionary like .keys(), .values()
Example:
def count_char(string):
dict = {}
count = 0
for i in string :
if i in dict.keys():
dict[i] +=1
else:
dict[i] = 1
for j in dict.values():
count += j
print(dict)
print(count)

Related

How to write a Python program to count the number of characters (character frequency) in a string? [duplicate]

This question already has answers here:
Counting Letter Frequency in a String (Python) [duplicate]
(13 answers)
Closed 16 hours ago.
def character_frequency(string):
for i in string:
count = 0
print(i,":", count, end = ", ")
count += 1
return count
print(character_frequency("dortmund"))
My goal is to print each letter and see how many times that letter exists in the string.
I tried print each letter and the use a variable called count to iterate over each letter and see how many times that letter exists in the string.
You can use collection.Counter class, from the documentation:
A Counter is a dict subclass for counting hashable objects. It is a collection where elements are stored as dictionary keys and their counts are stored as dictionary values. Counts are allowed to be any integer value including zero or negative counts. The Counter class is similar to bags or multisets in other languages.
Elements are counted from an iterable or initialized from another mapping (or counter):
c = Counter() # a new, empty counter
c = Counter('gallahad') # a new counter from an iterable
c = Counter({'red': 4, 'blue': 2}) # a new counter from a mapping
c = Counter(cats=4, dogs=8) # a new counter from keyword args
Counter objects have a dictionary interface except that they return a zero count for missing items instead of raising a KeyError:
c = Counter(['eggs', 'ham'])
c['bacon'] # count of a missing element is zero
Setting a count to zero does not remove an element from a counter. Use del to remove it entirely:
c['sausage'] = 0 # counter entry with a zero count
del c['sausage'] # del actually removes the entry
New in version 3.1.
Changed in version 3.7: As a dict subclass, Counter inherited the capability to remember insertion order. Math operations on Counter objects also preserve order. Results are ordered according to when an element is first encountered in the left operand and then by the order encountered in the right operand.
You can then just print the Counter object, use the pprint library, or write some pretty printing code yourself.

I just want to print the key, not their index

I need to print the keys + their values and it always prints the index of the key too, how can I fix that?
def task_3_4(something:str):
alphabet =list(string.ascii_letters)
i = 0
k=0
while i < len(alphabet):
dicts = {alphabet[i]: 0}
count = something.count(alphabet[i])
dicts[i] = count
if 0 < count:
for k in dicts:
print(k)
i = i+1
Based on the code it seems like you are trying to do some sort of counter of different characters in the string?
There is no index. your "index" is the "i" iterator you are using for your while loop. This simply makes a new key in dicts as called by dicts[i]. Thus when you call the print loop, it just iterates through and reads out I as well.
Try:
dicts[alphabet[i]] = count
Also your print function only prints out the key of the dict entry instead of the key-value pair. to do that you can try:
for k in dicts:
print(k,dicts[k])
Try reading up on the python docs for dicts.
https://docs.python.org/3/tutorial/datastructures.html

Variable not reassigned when changed in for loop

The goal of this code is to count the word that appears the most within the given list. I planned to do this by looping through the dictionary. If a word appeared a greater number of times than the value stored in the variable rep_num, it was reassigned. Currently, the variable rep_num remains 0 and is not reassigned to the number of times a word appears in the list. I believe this has something to do with trying to reassign it within a for loop, but I am not sure how to fix the issue.
def rep_words(novel_list):
rep_num=0
for i in range(len(novel_list)):
if novel_list.count(i)>rep_num:
rep_num=novel_list.count(i)
return rep_num
novel_list =['this','is','the','story','in','which','the','hero','was','guilty']
In the given code, 2 should be returned, but 0 is returned instead.
In you for loop you are iterating over the numbers and not list elements themselves,
def rep_words(novel_list):
rep_num=0
for i in novel_list:
if novel_list.count(i)>rep_num:
rep_num=novel_list.count(i)
return rep_num
You're iterating over a numeric range, and counting the integer i, none of which values exist in the list at all. Try this instead, which returns the maximum frequency, and optionally a list of words which occur that many times.
novel_list =['this','is','the','story','in','which','the','hero','was','guilty']
def rep_words(novel_list, include_words=False):
counts = {word:novel_list.count(word) for word in set(novel_list)}
rep = max(counts.values())
word = [k for k,v in counts.items() if v == rep]
return (rep, word) if include_words else rep
>>> rep_words(novel_list)
2
>>> rep_words(novel_list, True)
(2, ['the'])
>>> rep_words('this list of words has many words in this list of words and in this list of words is this'.split(' '), True)
(4, ['words', 'this'])
You've an error in your function (you're counting the index, not the value), write like this:
def rep_words(novel_list):
rep_num=0
for i in novel_list:
if novel_list.count(i)>rep_num: #you want to count the value, not the index
rep_num=novel_list.count(i)
return rep_num
Or you may try this too:
def rep_words(novel_list):
rep_num=0
for i in range(len(novel_list)):
if novel_list.count(novel_list[i])>rep_num:
rep_num=novel_list.count(novel_list[i])
return rep_num

Mutating strings in python

My brain cannot comprehend why this isn't working. I'm not very experienced and just trying to practice loops.
I'm trying to create a function that takes a string (currently one word) and capitalizes letters at random. With this code python throws a TypeError: list indices must be integers or slices, not strings
Here's what I have:
import random
list = []
def hippycase(string):
for letter in string:
list.append(letter)
for index in list:
if random.randint(1,2) == 1:
list[index] = list[index].upper()
else:
list[index] = list[index].lower()
return list
print(hippycase("pineapple"))
Any ideas or tips? Thanks
EDIT: Since this has been marked as a duplicate as someone thinks is at the following link, I'll try and clear up what is different:
Accessing the index in Python 'for' loops
I'm not trying to actively seek the index, I'm just practicing for loops which coincidentally goes through the index of the iterable sequentially. I also think if a fellow noob coder is searching this might be more helpful.
Here's a slightly improved version of your code
def hippycase(string):
charlist = []
for char in string:
if random.randint(1,2) == 1:
charlist.append(char.upper())
else:
charlist.append(char.lower())
return charlist
Notice that in this version we're looking only at the characters in your string, we don't care about the indices - this helps to reduce confusion.
If I were writing this to actually "hippycase" a string I would probably return "".join(charlist), so the calling function would get back a string (which is what they probably expect)
Also, it is bad practice to overwrite the list reserved word.
The variable "index" that you are using is a letter from the string, because you are iterating over it. To fix this error, use the range() function, which will allow you to access each element in the list by index:
list = []
def hippycase(string):
for letter in string:
list.append(letter)
for index in range(len(list)): #here, we are accessing the elements by index
if random.randint(1,2) == 1:
list[index] = list[index].upper()
else:
list[index] = list[index].lower()
return list
print(hippycase("pineapple"))
Another way is simple list comprehension:
the_string = "pineapple"
print ''.join([i.upper() if random.randint(1, 2) == 1 else i for i in the_string])

function would not change the parameter as wanted

here is my code
def common_words(count_dict, limit):
'''
>>> k = {'you':2, 'made':1, 'me':1}
>>> common_words(k,2)
>>> k
{'you':2}
'''
new_list = list(revert_dictionary(count_dict).items())[::-1]
count_dict = {}
for number,word in new_list:
if len(count_dict) + len(word) <= limit:
for x in word:
count_dict[x] = number
print (count_dict)
def revert_dictionary(dictionary):
'''
>>> revert_dictionary({'sb':1, 'QAQ':2, 'CCC':2})
{1: ['sb'], 2: ['CCC', 'QAQ']}
'''
reverted = {}
for key,value in dictionary.items():
reverted[value] = reverted.get(value,[]) + [key]
return reverted
count_dict = {'you':2, 'made':1, 'me':1}
common_words(count_dict,2)
print (count_dict)
what i expected is to have the count_dict variable to change to {'you':2}.
It did work fine in the function's print statement, but not outside the function..
The problem, as others have already written, is that your function assigns a new empty dictionary to count_dict:
count_dict = {}
When you do this you modify the local variable count_dict, but the variable with the same name in the main part of your program continues to point to the original dictionary.
You should understand that you are allowed to modify the dictionary you passed in the function argument; just don't replace it with a new dictionary. To get your code to work without modifying anything else, you can instead delete all elements of the existing dictionary:
count_dict.clear()
This modifies the dictionary that was passed to the function, deleting all its elements-- which is what you intended. That said, if you are performing a new calculation it's usually a better idea to create a new dictionary in your function, and return it with return.
As already mentioned, the problem is that with count_dict = {} you are not changing the passed in dictionary, but you create a new one, and all subsequent changes are done on that new dictionary. The classical approach would be to just return the new dict, but it seems like you can't do that.
Alternatively, instead of adding the values to a new dictionary, you could reverse your condition and delete values from the existing dictionary. You can't use len(count_dict) in the condition, though, and have to use another variable to keep track of the elements already "added" to (or rather, not removed from) the dictionary.
def common_words(count_dict, limit):
new_list = list(revert_dictionary(count_dict).items())[::-1]
count = 0
for number,word in new_list:
if count + len(word) > limit:
for x in word:
del count_dict[x]
else:
count += len(word)
Also note that the dict returned from revert_dictionary does not have a particular order, so the line new_list = list(revert_dictionary(count_dict).items())[::-1] is not guaranteed to give you the items in any particular order, as well. You might want to add sorted here and sort by the count, but I'm not sure if you actually want that.
new_list = sorted(revert_dictionary(count_dict).items(), reverse=True)
just write
return count_dict
below
print count_dict
in function common_words()
and change
common_words(count_dict,2)
to
count_dict=common_words(count_dict,2)
So basically you need to return value from function and store that in your variable. When you are calling function and give it a parameter. It sends its copy to that function not variable itself.

Categories

Resources