Program is repeating itself -can't figure out why - python

This is my program so far...it takes a message (input from user) and tells the user how many A's are in the program, how many B's, etc. Except when I input a message such as "Dad", it'll tell me how many D's there are twice instead of just saying everything once.
It says:
D ... 2
A ... 1
D ... 2
I want it to say:
A ... 1
D ... 2
How do I fix this without using zip, and without importing anything?
message=input("what is your message?").upper()
alphabet=["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]
count=[0]*len(alphabet)
for i in message:
if i in alphabet:
count[alphabet.index(i)]+=1
for i in message:
print (i,"...",count[alphabet.index(i)])
(Thanks to Uriel Eli for helping me get the program this far btw).

I don't agree with your approach here. You have actually over complicated this. The proper way to solve this is to actually use a dictionary to keep track of all the letters in the string and keep a count every time the same character comes up. Note, this also sticks to the rule of not importing anything.
Furthermore, this removes the necessity to have a list of letters to check against as well.
Also, if you need to count upper and lower case characters separtely, do not call upper at the end of your input. Just remove it. If you have to count upper and lower case as the same character, then you can leave it.
message=input("what is your message?").upper()
d = {}
for c in message:
if c in d:
d[c] += 1
else:
d[c] = 1
Demo
what is your message?thisisastringofthings
{'H': 1, 'F': 0, 'O': 0, 'R': 0, 'G': 1, 'S': 3, 'T': 2, 'A': 0, 'I': 3, 'N': 1}
To provide an output similar to what you are expecting, you just need to iterate through your final result and print:
for character, count in d.items():
print("{} ... {}".format(character, count))
Finally, just for the sake of showing the best way to do this, is to actually use Counter from collections:
>>> from collections import Counter
>>> Counter("thisisastring")
Counter({'s': 3, 'i': 3, 't': 2, 'h': 1, 'n': 1, 'a': 1, 'r': 1, 'g': 1})

Just for future reference, and I know that you CANT import anything now. The best way probably would be:
from collections import Counter
message=input("what is your message?").upper()
print(Counter(message))
# Counter({'D': 2, 'A': 1})

Your second for loop is iterating through message, so if the user input DAD (well... after upper casing it), you're gonna get:
message == DAD
i = D --> Shows 2
i = A --> Shows 1
i = D --> Shows 2 (again)
Maybe you'd want to iterate through count, keeping the index that you are iterating (to use it latter to match it with the alphabet list). Something like that:
for index, num_occurences in enumerate(count):
if num_occurences > 0:
print("Match found at i=%s which corresponds with alphabet[%s]=%s" %
(index, index, alphabet[index]))
print(alphabet[index], "...", num_occurences)
You should check what enumerate does.
If you still want to iterate through message, you can do it, keeping track of what letter did you already display using an auxiliary set (so you don't show the same letter again)
already_shown_letters = set()
for i in message:
if i not in already_shown_letters:
print (i,"...",count[alphabet.index(i)])
already_shown_letters.add(i)

Related

how to find the most popular letter in a string that also has the lowest ascii value

Implement the function most_popular_character(my_string), which gets the string argument my_string and returns its most frequent letter. In case of a tie, break it by returning the letter of smaller ASCII value.
Note that lowercase and uppercase letters are considered different (e.g., ‘A’ < ‘a’). You may assume my_string consists of English letters only, and is not empty.
Example 1: >>> most_popular_character("HelloWorld") >>> 'l'
Example 2: >>> most_popular_character("gggcccbb") >>> 'c'
Explanation: cee and gee appear three times each (and bee twice), but cee precedes gee lexicographically.
Hints (you may ignore these):
Build a dictionary mapping letters to their frequency;
Find the largest frequency;
Find the smallest letter having that frequency.
def most_popular_character(my_string):
char_count = {} # define dictionary
for c in my_string:
if c in char_count: #if c is in the dictionary:
char_count[c] = 1
else: # if c isn't in the dictionary - create it and put 1
char_count[c] = 1
sorted_chars = sorted(char_count) # sort the dictionary
char_count = char_count.keys() # place the dictionary in a list
max_per = 0
for i in range(len(sorted_chars) - 1):
if sorted_chars[i] >= sorted_chars[i+1]:
max_per = sorted_chars[i]
break
return max_per
my function returns 0 right now, and I think the problem is in the last for loop and if statement - but I can't figure out what the problem is..
If you have any suggestions on how to adjust the code it would be very appreciated!
Your dictionary didn't get off to a good start by you forgetting to add 1 to the character count, instead you are resetting to 1 each time.
Have a look here to get the gist of getting the maximum value from a dict: https://datagy.io/python-get-dictionary-key-with-max-value/
def most_popular_character(my_string):
# NOTE: you might want to convert the entire sting to upper or lower case, first, depending on the use
# e.g. my_string = my_string.lower()
char_count = {} # define dictionary
for c in my_string:
if c in char_count: #if c is in the dictionary:
char_count[c] += 1 # add 1 to it
else: # if c isn't in the dictionary - create it and put 1
char_count[c] = 1
# Never under estimate the power of print in debugging
print(char_count)
# max(char_count.values()) will give the highest value
# But there may be more than 1 item with the highest count, so get them all
max_keys = [key for key, value in char_count.items() if value == max(char_count.values())]
# Choose the lowest by sorting them and pick the first item
low_item = sorted(max_keys)[0]
return low_item, max(char_count.values())
print(most_popular_character("HelloWorld"))
print(most_popular_character("gggcccbb"))
print(most_popular_character("gggHHHAAAAaaaccccbb 12 3"))
Result:
{'H': 1, 'e': 1, 'l': 3, 'o': 2, 'W': 1, 'r': 1, 'd': 1}
('l', 3)
{'g': 3, 'c': 3, 'b': 2}
('c', 3)
{'g': 3, 'H': 3, 'A': 4, 'a': 3, 'c': 4, 'b': 2, ' ': 2, '1': 1, '2': 1, '3': 1}
('A', 4)
So: l and 3, c and 3, A and 4
def most_popular_character(my_string):
history_l = [l for l in my_string] #each letter in string
char_dict = {} #creating dict
for item in history_l: #for each letter in string
char_dict[item] = history_l.count(item)
return [max(char_dict.values()),min(char_dict.values())]
I didn't understand the last part of minimum frequency, so I make this function return a maximum frequency and a minimum frequency as a list!
Use a Counter to count the characters, and use the max function to select the "biggest" character according to your two criteria.
>>> from collections import Counter
>>> def most_popular_character(my_string):
... chars = Counter(my_string)
... return max(chars, key=lambda c: (chars[c], -ord(c)))
...
>>> most_popular_character("HelloWorld")
'l'
>>> most_popular_character("gggcccbb")
'c'
Note that using max is more efficient than sorting the entire dictionary, because it only needs to iterate over the dictionary once and find the single largest item, as opposed to sorting every item relative to every other item.

Counting only the frequency of letters in a string

I am trying to make my program count everything but numbers in a string, and store it in a dictionary.
So far I have this:
string = str(input("Enter a string: "))
stringUpper = string.upper()
dict = {}
for n in stringUpper:
keys = dict.keys()
if n in keys:
dict[n] += 1
else:
dict[n] = 1
print(dict)
I just want the alphabetical numbers quantified, but I cannot figure out how to exclude the non-alphabetical characters.
Basically there are multiple steps involved:
Getting rid of the chars that you don't want to count
Count the remaining
You have several options available to do these. I'll just present one option, but keep in mind that there might be other (and better) alternatives.
from collections import Counter
the_input = input('Enter something')
Counter(char for char in the_input.upper() if char.isalpha())
For example:
Enter something: aashkfze3f8237rhbjasdkvjuhb
Counter({'A': 3,
'B': 2,
'D': 1,
'E': 1,
'F': 2,
'H': 3,
'J': 2,
'K': 2,
'R': 1,
'S': 2,
'U': 1,
'V': 1,
'Z': 1})
So it obviously worked. Here I used collections.Counter to count and a generator expression using str.isalpha as condition to get rid of the unwanted characters.
Note that there are several bad habits in your code that will make your life more complicated than it needs to be:
dict = {} will shadow the built-in dict. So it's better to choose a different name.
string is the name of a built-in module, so here a different name might be better (but not str which is a built-in name as well).
stringUpper = string.upper(). In Python you generally don't use camelCase but use _ to seperate word (i.e. string_upper) but since you only use it to loop over you might as well use for n in string.upper(): directly.
Variable names like n aren't very helpful. Usually you can name them char or character when iterating over a string or item when iterating over a "general" iterable.
You can use re to replace all non-alphabetical characters before doing any manipulation:
regex = re.compile('[^a-zA-Z]')
#First parameter is the replacement, second parameter is your input string
regex.sub('', stringUpper )
string = str(input("Enter a string: "))
stringUpper = string.upper()
dict = {}
for n in stringUpper:
if n not in '0123456789':
keys = dict.keys()
if n in keys:
dict[n] += 1
else:
dict[n] = 1
print(dict)
for n in stringUpper:
if n.isalpha()
dict[n] += 1
else:
dict[n] = 1
print(dict)
You can check string for alphanumeric
n.isalnum()
for aphabetic:
n.isalpha()
So your code will be like:
dict = {}
for n in stringUpper:
if n.isalpha():
keys = dict.keys()
if n in keys:
dict[n] += 1
else:
dict[n] = 1
print(dict)
else:
#do something....
While iterating, check if the lower() and upper() is the same for a character. If they are different from each other, then it is an alphabetical letter.
if n.upper() == n.lower():
continue
This should do it.

Turning a string into a dictionary

Having had a python class behind me, I was presented with this question in the next class and I seem to be having a mental block on how to even get started.
"Write a python program that asks the user for a string, then create the following dictionary: The values are the letters in the string, with the corresponding key being the place in the string. For example if the user entered the string “ABC123” then the dictionary would be: D = {‘A’:0, ‘B’:1, ‘C’:2, ‘1’:3, ‘2’:4, ‘3’:5}
I started with asking for the user input with something simple like
s = input('Enter string: ')
however, I do not know how to proceed to the next step. Any help would be much appreciated.
In [55]: s = input("Enter a string: ")
Enter a string: ABC123
In [56]: d = {char:i for i,char in enumerate(s)}
In [57]: d
Out[57]: {'C': 2, '1': 3, '2': 4, '3': 5, 'B': 1, 'A': 0}
Note however, that if there are repeated characters in the user's input, d will have the index of the last occurrence of each character:
In [62]: s = input("Enter a string: ")
Enter a string: ABC123A
In [63]: d = {char:i for i,char in enumerate(s)}
In [64]: d
Out[64]: {'C': 2, '1': 3, '2': 4, '3': 5, 'B': 1, 'A': 6}
this?
def dict():
user_input = input("Please enter a string")
dictionary = {}
for i, j in enumerate(user_input):
dictionary[j] = i
print(dictionary)
dict("ABC123")
Are you sure you need this output: D = {‘A’:0, ‘B’:1, ‘C’:2, ‘1’:3, ‘2’:4, ‘3’:5} and not D = {0:'A', 1:'B', 2:'C'...}? You can flip the key:values, but they will be unordered then (e.g. you would get something like: D = {‘B’:1, ‘3’:5, ‘A’:0, ‘C’:2, ‘1’:3, ‘2’:4 } or any other random combination).
It sounds like you are getting started with learning python. Welcome to a beautiful programming language. People are very helpful here, but you need to show some effort and initiative. This is not a place to get quick fix solutions. People may provide them to you, but you'll never learn.
I assume this was a HW related question? Unless I'm mistaken (someone please feel free to correct me), the output you are seeking is difficult, if not impossible to create (e.g in that specific order you want). I encourage you to read about python dictionaries.
Try and run this:
#user = input("Give me a string:")
#Just for demo purpose, lets
#stick with your orig example
user = "ABC123"
ls =[] #create empty list
d = {} #create empty dictionary
#Try to figure out and understand
#what the below code does
#what is a list, tuple, dict?
#what are key:values?
for l in enumerate(user):
ls.append(l)
for k,v in ls:
d[k] = v
print('first code output')
print(ls)
print(d)
#What/how does enumerate work?
#the below will generate a
#ordered dict by key
for k,v in enumerate(user):
d[k] = v
print('2nd code output')
print(d)
#you want to flip your key:value
#output, bases on origibal question
#notice what happens
#run this a few times
print('3rd code output')
print(dict(zip(d.values(), d.keys())))
#You can get the order you want,
#but as a list[(tuple)], not as
#a dict at least in the output
#from your orig question
print(list(zip(d.values(), d.keys())))
Unless Im wrong, and someone more experienced can chime in, you cant get the "ordered" output in the format you want for your dictionary.
I'm on a mobile device, so anyone please feel free to correct things.

key error: 'x' --> adding key value pair in for loop, key being char

I am a beginner in python and I am trying to solve a coding problem, got this error. Don't understand why ? I went through a couple of Q/A's here but they don't seem to solve my problem. Essentially what I am trying to do is iterate over a string, through its characters and fill these characters in a dictionary. With characters being the keys and values being the number of times these characters appeared. So I'm trying the following:
def myfunc(mystring):
for i in mystring:
if charCounter[i]:
charCounter[i] += 1
charCounter[i] = 1
mystring = "hello! how are you ?"
myfunc(mystring)
and Im getting following error:
File "xyq.py", line 3, in myfunc
if CharCounter[i]:
KeyError: 'h'
Can someone please suggest, where am I going wrong ? And if possible how can I improve the code ?
Thanks
You need to check if i is in charCounter before you try to retrieve it:
if i in charCounter:
charCounter[i] += 1
else:
charCounter[i] = 1
Or alternatively:
if charCounter.get(i):
...
if charCounter[i]:
throws KeyError if the key does not exist. What you want to do isuse if i in charCounter: instead:
if i in char_counter:
char_counter[i] += 1
else:
char_counter[i] = 1
Alternatively you could use get which gets the value if it exists, or returns the second (optional) value if it didn't exist:
char_counter[i] = char_counter.get(i, 0) + 1
However this counting pattern is so popular that a whole class exists for it: collections.Counter:
from collections import Counter
def my_func(my_string):
return Counter(my_string)
Example:
>>> counts = my_func('hello! how are you ?')
>>> counts
Counter({' ': 4, 'o': 3, 'h': 2, 'l': 2, 'e': 2, '!': 1, 'r': 1, 'a': 1,
'?': 1, 'w': 1, 'u': 1, 'y': 1})
>>> counts[' ']
4
collections.Counter is a subclass of dictionary, so it would behave in the same way that an ordinary dictionary would do with item access and so forth.

Testing all Letters?

I am working on a script and the script should read a text file and test to see if the specified letters(a,a,r,d,v,a,r,k) are on each line. Im having a problem as I am trying to check for 3 different a's instead of just one. My code is below:
#Variables
advk = ['a','a','r','d','v','a','r','k']
textfile = []
number = 0
life = 0
for line in open('input.txt', 'rU'):
textfile.append(line.rstrip().lower())
while life == 0:
if all(word in textfile[number] for word in advk):
printed = number + 1
print ("Aardvark on line " + str(printed))
number+=1
if number == len(textfile):
life+=1
else:
number+=1
Everytime you want to count something in python, keep the Counter class in mind.
from collections import Counter
advk = Counter(['a','a','r','d','v','a','r','k'])
with open('input.txt', 'rU') as file:
for i, line in enumerate(file.readlines()):
if not advk - Counter(line.lower()):
print ("Aardvark on line " + str(i+1))
Given the input line
dffdaardvarksdsda
the Counter would look like these
Counter({'d': 5, 'a': 4, 'f': 2, 's': 2, 'r': 2, 'k': 1, 'v': 1})
and
Counter({'a': 3, 'r': 2, 'd': 1, 'k': 1, 'v': 1})
for your list of letters to search.
We use a trick by simply substracting the two Counters advl - Counter(line.lower()) and check if the resulting Counter has no elements left.
Other things to note:
You can use the with statement to ensure your file gets closed.
You can use enumerate instead counting the line numbers.
if advk list is variable and contents are read from somewhere else then to maintain unique elements in the list you can convert it to set and check.
advk = ['a','a','r','d','v','a','r','k']
advk = list(set(advk))
This makes advk a unique list and avoids check multiple 'a's in the line.
# If the line "ardvrk" should match, this is a solution:
chars=set('aardvark')
for nr, line in enumerate(open('input.txt', 'rU')):
if not chars-set(line): # is subset?
print 'match', nr, line,

Categories