Newbie here...Trying to write a function that takes a string and replaces all the characters with their respective dictionary values.
Here is what I have:
def alphabet_position(text):
dict = {'a':'1','b':'2','c':'3','d':'4','e':'5','f':'6','g':'7','h':'8':'i':'9','j':'10','k':'11','l':'12','m':'13','n':'14','o':'15','p':'16','q':'17','r':'18','s':'19','t':'20','u':'21','v':'22','w':'23','x':'24','y':'25','z':'26'}
text = text.lower()
for i in text:
if i in dict:
new_text = text.replace(i, dict[i])
print (new_text)
But when I run:
alphabet_position("The sunset sets at twelve o' clock.")
I get:
the sunset sets at twelve o' cloc11.
meaning it only changes the last character in the string. Any ideas? Any input is greatly appreciated.
Following your logic you need to create a new_text string and then iteratively replace its letters. With your code, you are only replacing one letter at a time, then start from scratch with your original string:
def alphabet_position(text):
dict = {'a':'1','b':'2','c':'3','d':'4','e':'5','f':'6','g':'7','h':'8','i':'9','j':'10','k':'11','l':'12','m':'13','n':'14','o':'15','p':'16','q':'17','r':'18','s':'19','t':'20','u':'21','v':'22','w':'23','x':'24','y':'25','z':'26'}
new_text = text.lower()
for i in new_text:
if i in dict:
new_text = new_text.replace(i, dict[i])
print (new_text)
And as suggested by Kevin, you can optimize a bit using set. (adding his comment here since he deleted it: for i in set(new_text):) Note that this might be beneficial only for large inputs though...
As your question is generally asking about "Alphabet position in python", I thought I could complement the already accepted answer with a different approach. You can take advantage of Python's string lib, char to int conversion and list comprehension to do the following:
import string
def alphabet_position(text):
alphabet = string.ascii_lowercase
return ''.join([str(ord(char)-96) if char in alphabet else char for char in text])
Your approach is not very efficient. You are recreating the string for every character.
There are 5 e characters in your string. This means replace is called 5 times, even though it only actually needs to do anything the first time.
There is another approach that might be more efficient. We cant use str.translate unfortunately, as it's remit is one to one replacements.
We just iterate the input and produce a new string character by character.
def alphabet_position2(text):
d = {L: str(i) for i, L in enumerate('abcdefghijklmnopqrstuvwxyz', 1)}
result = ''
for t in text.lower():
result += d.get(t, t)
return result
This is a pretty simple approach with list comprehension.
Generate k:v in this format from string module, 1:b instead of b:1
import string
def alphabet_position(text):
alphabeths = {v: k for k, v in enumerate(string.ascii_lowercase, start=1)}
return " ".join(str(alphabeths.get(char)) for char in text.lower() if char in alphabeths.keys())
Related
I'm new to Python and I'm stuck in an exercise which tells me to provide a script printing every possible pairs of two letters, only lower case, one by line, ordered alphabetically and that is the closest thing that I could do
import string
x=string.ascii_lowercase
y=list(x)
for i in y:
print(i,end='')
for g in y:
print(g)
You only print the first letter of each pair once.
from string import ascii_lowercase as lowercase_letters
for first_letter in lowercase_letters:
for second_letter in lowercase_letters:
print(first_letter + second_letter)
Additionally:
You don't need to convert the string to a list, you can loop over a string just fine. In fact, that's how list(some_string) works!
I used more readable variable names.
Using from ... import means you don't need to have the additional assignment.
You need to print the i letter in the second for loop
import string
x=string.ascii_lowercase
for i in x:
for g in x:
print(i,g)
So the program will go through every letter in the first loop and will print then the whole alphabet, one by one, as the second letter in the second loop
word_list = ['WELCOME']
double_letters = []
for word in word_list:
for i,j in enumerate(word):
x = word[i:i+2]
if len(x) == 2:
double_letters.append(x)
print(double_letters)
If you are given a list of words. Then this is one possible way
Try this code this will print in alphabetic order
You have studied ASCII code so what it does is it loops through 97 to 122 which contains all the alphabets and then it joins them.
for firstchar in range(97, 123):
for secondchar in range(97, 123):
print(chr(firstchar) + chr(secondchar))
If use string module it is very simple task:
import string
for firstchar in string.ascii_lowercase:
for secondchar in string.ascii_lowercase:
print(firstchar + secondchar)
The problem at hand is that given a string S, we can transform every letter individually to be lowercase or uppercase to create another string.
Desired result is a list of all possible strings we could create.
Eg:
Input:
S = "a1b2"
Output:
["a1b2", "a1B2", "A1b2", "A1B2"]
I see the below code generates the correct result, but I'm a beginner in Python and can you help me understand how does loop line 5 & 7 work, which assign value to res.
def letterCasePermutation(self, S):
res = ['']
for ch in S:
if ch.isalpha():
res = [i+j for i in res for j in [ch.upper(), ch.lower()]]
else:
res = [i+ch for i in res]
return res
The result is a list of all possible strings up to this point. One call to the function handles the next character.
If the character is a non-letter (line 7), the comprehension simply adds that character to each string in the list.
If the character is a letter, then the new list contains two strings for each one in the input: one with the upper-case version added, one for the lower-case version.
If you're still confused, then I strongly recommend that you make an attempt to understand this with standard debugging techniques. Insert a couple of useful print statements to display the values that confuse you.
def letterCasePermutation(self, S):
res = ['']
for ch in S:
print("char = ", ch)
if ch.isalpha():
res = [i+j for i in res for j in [ch.upper(), ch.lower()]]
else:
res = [i+ch for i in res]
print(res)
return res
letterCasePermutation(None, "a1b2")
Output:
char = a
['A', 'a']
char = 1
['A1', 'a1']
char = b
['A1B', 'A1b', 'a1B', 'a1b']
char = 2
['A1B2', 'A1b2', 'a1B2', 'a1b2']
Best way to analyze this code is include the line:
print(res)
at the end of the outer for loop, as first answer suggests.
Then run it with the string '123' and the string 'abc' which will isolate the two conditionals. This gives the following output:
['1']
['12']
['123']
and
['A','a']
['AB','Ab','aB','ab']
['ABC','ABc','AbC','aBC','Abc','aBc','abC','abc']
Here we can see the loop is just taking the previously generated list as its input, and if the next string char is not a letter, is simply tagging the number/symbol onto the end of each string in the list, via string concatenation. If the next char in the initial input string is a letter, however, then the list is doubled in length by creating two copies for each item in the list, while simultaneously appending an upper version of the new char to the first copy, and a lower version of the new char to the second copy.
For an interesting result, see how the code fails if this change is made at line 2:
res = []
Hi I'm doing the anti_vowel function, which basically takes out all of the vowels from the input. I'm confused about this code. Why doesn't it work? (For the last word "word") The output for "Hey look words!" is:
Hy lk words!
If anyone can help, thank you so so much!
def anti_vowel(text):
l = []
s = ""
for i in text:
l.append(i)
for i in l:
if i in "aeiouAEIOU":
x = l.index(i)
l.pop(x)
print l
print "".join(l)
anti_vowel("Hey look words!")
The output is:
Hy lk Wrds!
Modifying an iterator (your list) while looping over it will end up yielding very unexpected results, and should always be avoided. In your particular case, as you delete your list, you are actually reducing it, and therefore actually ending it "earlier" than you should.
What you should be doing instead is collecting your data in a new list based on what you are trying to filter. So, instead of popping, instead you should check for non-vowels and append to a new list. Taking your exact code and changing just that logic, you should be good:
def anti_vowel(text):
l = []
s = ""
for i in text:
l.append(i)
new_l = []
for i in l:
if i not in "aeiouAEIOU":
new_l.append(i)
print("".join(new_l))
So, running that code now, will yield the following output:
Hy lk wrds!
Now, to go over some areas in your code where you are doing some unnecessary steps that you can simplify. You do not need to loop through your string like that and create a new list at the beginning of your function. Your string can already be iterated over, so simply do exactly that using your string. In other words you do not need this:
l = []
s = ""
for i in text:
l.append(i)
So, instead, you can just start from:
new_l = []
for i in text:
if i not in "aeiouAEIOU":
new_l.append(i)
print("".join(new_l))
So, the above code now simply iterates over your string text, character-by-character, and we will check to make sure that each character does not match the vowels, and append it to our new list.
Finally, for the sake of really making this short. We can throw this in to a pretty little line making an expression that we can then call join on to create our string. Also! you don't need to check all cases since you can just keep your characters to a single casing by calling the lower method on your string you are iterating through to keep all under a single case, to make it simpler to check:
def anti_vowel(text):
return ''.join(c for c in text if c.lower() not in "aeiou")
print(anti_vowel("Hey look words!"))
You're deleting elements from the list as you iterate over it. You're actually shortening the list before the loop can even reach the '...words' part.
A couple of other things. If you want to convert a string to a list, you can just do:
myList = list(myString)
Next, when iterating, do iterate over a copy of the list.
for i in l[:]:
The [:] operator creates a spliced copy, and iterates over that. This is the big fix, and it'll get your code running as expected. For that particular input, you get Hy lk wrds!.
Simpler alternative? Don't even use a list. You can work with strings, using the str.replace function:
def anti_vowel(text):
newText = text[:]
for i in 'aeiouAEIOU':
newText = newText.replace(i, '')
print(newText)
return newText
newText = anti_vowel("Hey look words!")
print(newText)
Output:
Hy lk wrds!
An even simpler version? You can use str.translate:
>>> x = {c : '' for c in 'aeiouAEIOU'}
>>> "Hey look words!".translate(str.maketrans(x))
'Hy lk wrds!'
def anti_vowel(text):
new = ''
for char in text:
if char in "aeiou" or char in "AEIOU":
ala = text.replace(char, '')
try doing this. Hope it helps
You should never alter an iterable (list in this case) while you're iterating over it. Bad things can and do happen.
Here's a different and a bit simpler way to do it. Instead of removing vowels from a list, instead, we create an empty list, and put the constants into it:
def anti_vowel(text):
consts = []
for letter in text:
if letter not in "aeiouAEIOU":
consts.append(letter)
print "".join(consts)
anti_vowel("Hey look words!")
Output:
Hy lk wrds!
Since other answers have already provided you with an explanation of your problem, and showed how to fix your code, I'll show you how you can make your function much smaller and cleaner.
You can use a generator comprehension to filter out all of the vowels from your input, and use ''.join() to join each individual character back together:
>>> def anti_vowels(text):
return ''.join(c for c in text if c.lower() not in 'aeiou')
>>> anti_vowels('Hey look words!')
'Hy lk wrds!'
>>> anti_vowels('Hello, World!')
'Hll, Wrld!'
>>> anti_vowels('I love vowels!')
' lv vwls!'
>>> anti_vowels('Ronald Regan')
'Rnld Rgn'
>>> anti_vowels('Carts And BOxes')
'Crts nd Bxs'
>>>
The important part of the comprehension is the the if part. It will only add the current character to the generator if it is not a vowel. I've also eliminated the extra uppercase vowels by using c.lower(). This force c to become lower case, so we can treat the character as if it were case insensitive.
You can also easily extend this to allow the user to specify the vowels they want to filter out (such as y):
>>> def anti_vowels(text, vowels='aeiou'):
return ''.join(c for c in text if c.lower() not in vowels)
>>> anti_vowels('Hey look words!')
'Hy lk wrds!'
>>> anti_vowels('Hey look words!', vowels='aeiouy')
'H lk wrds!'
>>>
I need to be able to find an asterisk in a Python string, and then run the upper method on the subsequent character in that string. So suppose I have:
s*tring
I need to turn it into:
sTring
Though iteration over the characters of the String and replace is possible it is more efficient to make use of pattern matching. You can do this by re module's sub() method. Start by defining a lambda function to carry out the conversion process and then match and replace using re.sub() with this function. Hope this helps!
import re
txt = "s*tring"
callback = lambda pat: pat.group(0).replace("*", "").upper()
txt = re.sub("\*[a-z]", callback, txt)
print txt
Result:
>> python main.py
sTring
Remember this can used for sentences as well.. setting txt = "My *name is *c.*swadhikar"
Result:
>> python main.py
My Name is C.Swadhikar
You can do it a brute force way like this:
def str_upper(string):
my_list = list(string)
indexes = []
for char in my_list:
if char is "*":
indexes.append(my_list.index(char))
my_list.remove(char)
result = []
for i, letter in enumerate(my_list):
if i in indexes:
result.append(letter.upper())
else:
result.append(letter)
return "".join(result)
Output:
>>> str_upper("s*tring")
sTring
>>> str_upper("s*tri*ng")
sTriNg
This is also a much shorter pythonic solution:
def str_upper2(string):
return "".join(s[0].upper() + s[1:] for s in string.split('*'))
What is the most pythonic and/or efficient way to count the number of characters in a string that are lowercase?
Here's the first thing that came to mind:
def n_lower_chars(string):
return sum([int(c.islower()) for c in string])
Clever trick of yours! However, I find it more readable to filter the lower chars, adding 1 for each one.
def n_lower_chars(string):
return sum(1 for c in string if c.islower())
Also, we do not need to create a new list for that, so removing the [] will make sum() work over an iterator, which consumes less memory.
def n_lower_chars(string):
return len(filter(str.islower, string))
def n_lower_chars(string):
return sum(map(str.islower, string))
If you want to divide things a little more finely:
from collections import Counter
text = "ABC abc 123"
print Counter("lower" if c.islower() else
"upper" if c.isupper() else
"neither" for c in text)