Count number of occurrences of a character in a string - python

I'm just getting into Python and I'm building a program that analyzes a group of words and returns how many times each letter appears in the text. i.e 'A:10, B:3, C:5...etc'. So far it's working perfectly except that i am looking for a way to condense the code so i'm not writing out each part of the program 26 times. Here's what I mean..
print("Enter text to be analyzed: ")
message = input()
A = 0
b = 0
c = 0
...etc
for letter in message:
if letter == "a":
a += 1
if letter == "b":
b += 1
if letter == "c":
c += 1
...etc
print("A:", a, "B:", b, "C:", c...etc)

There are many ways to do this. Most use a dictionary (dict). For example,
count = {}
for letter in message:
if letter in count: # saw this letter before
count[letter] += 1
else: # first time we've seen this - make its first dict entry
count[letter] = 1
There are shorter ways to write it, which I'm sure others will point out, but study this way first until you understand it. This sticks to very simple operations.
At the end, you can display it via (for example):
for letter in sorted(count):
print(letter, count[letter])
Again, there are shorter ways to do this, but this way sticks to very basic operations.

You can use Counter but #TimPeters is probably right and it is better to stick with the basics.
from collections import Counter
c = Counter([letter for letter in message if letter.isalpha()])
for k, v in sorted(c.items()):
print('{0}: {1}'.format(k, v))

Related

Number of words in text you can fully type using this keyboard

There is such a task with Leetcode. Everything works for me when I press RUN, but when I submit, it gives an error:
text = "a b c d e"
brokenLetters = "abcde"
Output : 1
Expected: 0
def canBeTypedWords(self, text, brokenLetters):
for i in brokenLetters:
cnt = 0
text = text.split()
s1 = text[0]
s2 = text[1]
if i in s1 and i in s2:
return 0
else:
cnt += 1
return cnt
Can you please assist what I missed here?
Everything work exclude separate letters condition in a text.
So consider logically what you have to do, then write that algorithmically.
Logically, you have a list of words, a list of broken letters, and you need to return the count of words that have none of those broken letters in them.
"None of those broken letters in them" is the important bit -- if even one broken letter is in the word, it's no good.
def count_words(broken_letters, word_list) -> int:
words = word_list.split() # split on spaces
broken_letters = set(broken_letters) # we'll be doing membership checks
# on this kind of a lot, so changing
# it to a set is more performant
count = 0
for word in words:
for letter in word:
if letter in broken_letters:
# this word doesn't work, so break out of the
# "for letter in word" loop
break
else:
# a for..else block is only entered if execution
# falls off the bottom naturally, so in this case
# the word works!
count += 1
return count
This can, of course, be written much more concisely and (one might argue) idiomatically, but it is less obvious to a novice how this code works. As exercise to the reader: see if you can understand how this code works and how you might modify it if the exercise was, instead, giving you all the letters that work rather than the letters that are broken.
def count_words(broken_letters, word_list) -> int:
words = word_list.split()
broken_letters = set(broken_letters)
return sum((1 for word in words if all(lett not in broken_letters for lett in word)))

Python: Moving on to the next letter on For Loop

How can I move on to the next letter in a for loop before 1st iteration finishes?
s = 'mmmmbobob'
for letter in s:
if letter is 'b':
s = s + 1 <<<<<<<<<RIGHT HERE<<<<<<<<<
if letter is 'o':
s = s + 1 <<<<<<<<<THEN HERE<<<<<<<<<
if letter is "b":
counter_bob += 1
else:
break
else:
break
else:
continue
print('Number of times bob occurs is: %d' % (bob_name_counter))
Currently, you're trying to add 1 to the string s, which will throw a TypeError. Even if s was an int, incrementing it in this fashion would not move to the next iteration of the loop in Python (or any language I know).
You can use the keyword continue to move to the next iteration of a loop immediately. Docs here: https://docs.python.org/3/tutorial/controlflow.html#break-and-continue-statements-and-else-clauses-on-loops
However, I don't think that is exactly what you want to do here, since it looks like you are trying to count the occurrences of the substring 'bob' in your main string s.
Instead you should iterate over the indices of the characters of s and at each point check if the current character and next two together form the substring 'bob'. If so increment counter_bob.
An example refactor of your code with this in mind:
s = 'mmmmbobob'
counter_bob = 0
for i in range(len(s)):
if s[i:i+3] == 'bob':
counter_bob += 1
print('Number of times bob occurs is: %d' % (counter_bob))
Which prints:
Number of times bob occurs is: 2

Upper case characters every other character but ignoring symbols and spaces

I'm a novice working on a practice script of which I have 90% figured out but am stumped on one portion. I'm doing the mocking spongebob "challenge" on dmoj which asks you to make every other character of a given string upper case, but demands symbols and spaces to be ignored and only letters to be counted.
I and am able to make every other character upper case or lower case, but I am not sure how to ignore symbols and spaces? I'll drop what I have so far for critique. Thank you for your time.
meme1 = "I don't even know her like that"
meme2 = "You can't just make a new meme from a different Spongebob clip every
couple of months"
meme3 = "I must have listened to that latest Ed Sheeran song 10000 times!"
memeFIN1 = [""] * len(meme1)
memeFIN2 = [""] * len(meme2)
memeFIN3 = [""] * len(meme3)
memeFIN1[1::2] = meme1[1::2].upper()
memeFIN2[1::2] = meme2[1::2].upper()
memeFIN3[1::2] = meme3[1::2].upper()
memeFIN1[::2] = meme1[::2].lower()
memeFIN2[::2] = meme2[::2].lower()
memeFIN3[::2] = meme3[::2].lower()
memeFIN1 = "".join(memeFIN1)
memeFIN2 = "".join(memeFIN2)
memeFIN3 = "".join(memeFIN3)
print(memeFIN1)
print(memeFIN2)
print(memeFIN3)
EDIT:
All of the following solutions in the answers helped me come to my own, but none of them seemed to work entirely on their own. In cheesits solution, changing counter to start at 1 works, but not realizing that (as an utter noob) I did counters differently, essentially doing the same thing. This is the solution that worked for me:
meme1 = "I don't even know her like that"
meme2 = "You can't just make a new meme from a different Spongebob clip every couple of months"
meme3 = "I must have listened to that latest Ed Sheeran song 10000 times!"
def spongebobify(meme):
count = 0
char = []
for ch in meme:
if ch.isalpha() and count % 2 == 1:
char.append(ch.upper())
count += 1
elif ch.isalpha():
char.append(ch.lower())
count += 1
else:
char.append(ch)
return ''.join(char)
m1 = spongebobify(meme1)
m2 = spongebobify(meme2)
m3 = spongebobify(meme3)
print (m1)
print (m2)
print (m3)
If you want something readable, try this:
def spongebobify(phrase):
## Turn every character lowercase
phrase = phrase.lower()
## Keep track of how many letters you've seen
counter = 0
## Create a list to hold characters
chars = []
## Go through the entire string
for ch in phrase:
## If this is a letter, increment
if ch.isalpha():
counter += 1
## If this is a letter and our counter is odd:
if ch.isalpha() and counter % 2:
chars.append(ch.upper())
## Otherwise, just add it as-is
else:
chars.append(ch)
return ''.join(chars)
If you want a one liner (disregarding efficiency):
def spongebobify(phrase):
return ''.join([ch.lower() if ch.isalpha() and len([c for c in phrase[:i] if c.isalpha()]) % 2 else ch for i, ch in enumerate(phrase.upper())])
## Readable version:
#return ''.join([
# ch.lower()
# if ch.isalpha()
# and len([c for c in phrase[:i] if c.isalpha()]) % 2
# else ch
# for i, ch in enumerate(phrase.upper())
#])
you can use a bit to indicate which lower/upper you're currently looking at, toggling the bit whenever an alpha character is found.
def speak_like_spongebob(phrase):
case_bit = 0
res = []
for lower_upper in zip(phrase.lower(), phrase.upper()):
res.append(lower_upper[case_bit])
case_bit ^= lower_upper[0].isalpha()
return ''.join(res)
You need to use a loop, so you can increment a counter only when the character is a letter, and then check whether that counter is odd or even.
def mock_spongebob(input):
letters = 0
result = ""
for c in input:
if c.isalpha():
result += c.lower() if letters % 2 == 0 else c.upper()
letters += 1
else:
result += c
return result
As others have mentioned, you will need to iterate through each character in the strings, determine whether it's a character or a symbol, and act accordingly.
The following program would print every other character in uppercase, not counting non-alphabetic characters:
meme1 = "I don't even know her like that"
meme2 = "You can't just make a new meme from a different Spongebob clip every couple of months"
meme3 = "I must have listened to that latest Ed Sheeran song 10000 times!"
for meme in [meme1, meme2, meme3]:
count = 0
meme_mod = ""
for c in meme:
if not c.isalpha():
meme_mod += c
continue
elif count % 2 == 0:
meme_mod += c.lower()
else:
meme_mod += c.upper()
count += 1
print meme_mod
This program would output:
i DoN't EvEn KnOw HeR lIkE tHaT
yOu CaN't JuSt MaKe A nEw MeMe FrOm A dIfFeReNt SpOnGeBoB cLiP eVeRy CoUpLe Of MoNtHs
i MuSt HaVe LiStEnEd To ThAt LaTeSt Ed ShEeRaN sOnG 10000 tImEs!
Here's an article that shows how to write a SpongeBob Mocking Converter script in Python

Formatting two lists into a single dictionary

I'm coding a hangman game for my Computer Science class, and I'm trying to create a dictionary that has each character of the word given and a 0 to notate whether it's been guessed or not.
gamestart = 0
guesses = 5
gamewin = 0
while gamestart == 0:
word = input("Welcome to hangman!" + "\nEnter a word: ")
if word.find(" ") > -1:
print("\nSorry Please use one word only!\n")
elif word.find(" ") == -1:
gamestart = 1
for i in range(len(word)):
wordspacing = [0] * i
wordstore = list(word)
wordstore = dict(zip(wordspacing, wordstore))
print(wordstore)
however when I try to put the two lists I have together I get the output:
Welcome to hangman!
Enter a word: word
{0: 'r'}
Could someone identify the reason for this happening. I would also like a little bit of criticism in terms of efficiency.
The problem is that you are making a dictionary of 0 to letters, and each key can only have one value.
Try just using a dictionary comprehension
wordstore = {letter: 0 for letter in word}
To achieve the desired output using your method you need to switch the order of the zipped objects
wordstore = dict(zip(wordstore, wordspacing))
Also for wordspacing, you don't want to continually assign a value to wordspacing, plus you only end up with [0,0,0] instead of [0,0,0,0] since the last value of i is 3 and not 4. So go with the following
wordspacing = [0] * len(word)

Print two appearances of character found in python list

First time here (and a programming noob), hope I get the formatting correct!
I'm trying to make a function that will print out where in a list the occurence of a sought after letter is placed. The code below finds the letter and prints out where in the list the letter is i.e. if you search for 'a' the program will answer it's in the 2nd spot (x+1).
The problem is, if I search for a letter that have more than one occurrencies (for example the letter 'e'), the program finds the letter in both spots but in both cases prints out that it is in the 10th spot.
I'm trying to find out why, should be 10th and 17th in this case.
# store string in variable
solution = list('can you guess me')
guess = raw_input('What letter do you guess on? ')
# Search list
def search(guess):
nothing = 0
for x in solution:
if x == guess:
print x,
print "is in ",
print solution.index(x) + 1
nothing = 1
if nothing == 0:
print "Couldn't find ",
print guess
search(guess)
If choosing e, like this:
What letter do you think is in the answer? e
the program prints out:
e is in 11
e is in 11
I would like to know why. :/
How about this approach:
solution = 'This is the solution'
# Search list
def search(guess):
return [i for i,x in enumerate(solution) if x == guess]
guess = raw_input('Enter your guess: ')
result = search(guess)
if result:
positions = ','.join(str(i+1) for i in result)
print('{0} was found in positions {1}'.format(guess, positions))
else:
print('Sorry, {0} was not found!'.format(guess))
What we are doing here is stepping through the solution and if a character matches the guess, we return its position. If no characters match, then the method will return an empty list; which is a falsey value.
Then, we just check the return value of the method. If it is a list, we add 1 to the position (since list indices start from 0), and then print those out.
solution.index(x) does the same search for you, but will only ever return the first match.
Use enumerate() instead to create an index:
for i, x in enumerate(solution):
if x == guess:
print x,
print "is in ",
print i + 1
nothing = 1
The alternative approach would be to tell solution.index() where to start searching from. The previous position you printed, for example:
last = -1
for x in solution:
if x == guess:
print x,
print "is in ",
last = solution.index(x, last) + 1
print last
nothing = 1

Categories

Resources