This question already has answers here:
How to test multiple variables for equality against a single value?
(31 answers)
Closed 7 years ago.
I have a lot of repetition in my code, a prime example is when I'm doing a simple check to see if the first letter of a string is a vowel or not. The code I have is as follows :
if word[0] == 'a' or word[0] == 'e' or word[0] == 'i' or word[0] == 'o' or word[0] == 'u':
print 'An', word
else:
print 'A', word
This works fine but the amount of repetition leads me to think there could be an easy way to shorten this, I just don't know of it. I also tried this code:
if word[0] == 'a' or 'e' or 'i' or 'o' or 'u':
print 'An', word
else:
print 'A', word
However, this code returned True for every word, regardless of beginning letter.
So, just to clarify. The code works fine and it fully functional and I know I could define it as a function and just use that but it seems like it could easily be shortened and this knowledge would be useful on multiple projects.
Test for membership using in:
if word[0] in {"a","e","i","o","u"}
Also if word[0] == 'a' or 'e' or 'i' or 'o' or 'u' would always evaluate to True, you are basically checking if word[0] == "a" then if bool("e") which will always be True for any non empty string.
Not a big deal for a small test like you are doing but set lookups are 0(1) as opposed to 0(n) for a list, string etc. so a much more efficient solution when dealing with larger data or many repeated lookups.
You can also pass a tuple or letters to str.startswith:
if word[0].startswith(("a","e","i","o","u")):
If you want to ignore case, call word[0].lower() on the letter.
Test it using the keyword in.
word = "hello"
vowels = frozenset("aeiou")
if word[0] in vowels:
print "It's in!"
else:
print "It's not."
Note that you can have your vowels in anything iterable, set, list, string, dict, a generator function or whatever you like.
As pointed out by #MartijnPieters in the comments, the frozenset is the most optimised way to do this.
You could try with re module.
if re.match(r'(?i)[aeiou]$', word[0]):
This would handle both upper and lower case vowels. (?i) called case-insensitive modifier which helps to do a case-insensitive match. Since match function tries to match the string from the begining, you dont need to add the starting anchor ^. [aeiou] character class which matches a or e or i or o or u.
Related
What I'm trying to figure out is how to go back a position in a string.
Say I have a word and I'm checking every letter, but once I get to a "Y"
I need to check if the character before was a vowel or not. (I'm a beginner in this language so I'm trying to practice some stuff I did in C which is the language I'm studying at college).
I'm using a For loop to check the letters in the word but I don't know if there's any way to go back in the index, I know in C for example strings are treated like arrays, so I would have a For loop and once I get to a "Y", that would be my word[i] (i being the index of the position I'm currently at) so what I would normally do is check if word[i-1] in "AEIOUaeiou" (i-1 being the position before the one I'm currently at). Now I don't know how that can be done in python and it would be awesome if someone could give me a hand :(
One option is to iterate through by index, as you'd do in C:
word = "today"
for i in range(1, len(word)):
if word[i].lower() == 'y' and word[i-1].lower() in 'aeiou':
print(word[i-1:i+1])
Another is to zip the string with itself shifted by one character:
for x, y in zip(word, word[1:]):
if y.lower() == 'y' and x.lower() in 'aeiou':
print(x+y)
There's a good answer here already but I wanted to point out a more "C-like" way to iterate strings (or anything else).
Some people may considered it un-Pythonic but in my opinion it's often a good approach when writing certain algorithms:
word = "today"
len_word = len(word)
vowels = "aeiou"
i = 0
while i < len_word:
if word[i] == "y":
if word[i-1].lower() in vowels:
print(word[i-1])
i += 1
This approach gives you more flexibility, for example, you can do more complex things like "jumping" back and forth with the index, however, you also need to be more careful not to set the index to something that is out of range of the iterable.
You could use a regular expression here, e.g. to flag words which don't have a vowel before Y you could use:
inp = "blahYes"
if re.search(r'[^\WAEIOUaeiou_]Y', inp):
print("INVALID")
else:
print("VALID")
You can easily do this in the C style:
vowels = ['a', 'e', 'i', 'o', 'u']
for i in range (0, len(your_string):
if your_string[i].lower() == 'y':
# do your calculation here
if your_string[i-1].lower() in vowels:
print (f"String has vowel '{your_string[i-1]' at index {i-1} and has 'y' at i)
You could use your_string[i].lower() == 'y' so it will match both y and Y .
Or your can also use enumerate function.
for index, value in enumerate(your_string):
if val.lower() == 'y' :
# check if index-1 was a vowel
in Python, strings are iterable, so you can get the [i-1] element of a string
I am trying to determine if a given word is a palindrome.
The goal of my code is that the function will take a word, and remove it of any punctuation or spaces. If the length of the word is 0 or 1, it is returned that the word is a palindrome. I then check if the first and last letter are the same. If they aren't, it is returned that it is not a palindrome. If they first and last letters the same, I then want to replace those two letters with spaces and call my function again. The reason I replace the letters with spaces is so that it will be edited by my initial edit statements.
def palindrome(word):
editWord = word.strip(" ").strip("!").strip("?")
stringOne = "A palindrome"
stringTwo = "Not a palindrome"
if len(editWord) == 0 or len(editWord) == 1:
return stringOne
elif editWord[0] != editWord[-1]:
return stringTwo
else:
word = editWord.replace(editWord[0], " ").replace(editWord[-1], " ")
palindrome(word)
return stringOne
print(palindrome("area"))
When tested with single letters it functions properly, as well if I test words like 'are' which obviously is not a palindrome. However, if I call the word area it returns "A palindrome" when it is not. This makes it seem like it is not calling my function again. Any suggestions on why this is happening?
For recursion to work properly here, your else statement should say something along the lines of "the word is a palindrome if the outer characters are equal and the remainder is also a palindrome". Instead, your code is replacing all occurrences of the outer characters with spaces, checking if the word is a palindrome, and ignoring the result to always return "yes".
You can do a proper recursion using slicing instead of replacement:
else:
return palindrome(editWord[1:-1])
Another alternative to replacing the letters while still doing this recursively to to keep track of the index in the word and increment it on recursion. This saves you from having to make new slices on each recursion. In this case your edge case will be when the index is in the middle of the word.
def palindrome(word, i = 0):
if i >= len(word)//2:
return True
if word[i] != word[-(i+1)]:
return False
return palindrome(word, i+1)
palindrome("mrowlatemymetalworm") # true
I need your help about a small program I'm making.
The program checks if a word is True, False or invalid argument.
For example, I type e_silaba(ALO) and it verifies if the word is possible based on the letters in vowel.
My first question is, do I have to choose the size of my string (word)?
What better way do I have to see if the word doesn't belong to "vowel"? I know the way I made is wrong but I can't find a solution for that..
The way I made to check if the word is true only verifies the first two positions and I don't think it's a good idea to spam and's all over the place. Is there a way to easily verify each position of the string one by one to check if it belongs to, in this case, "vowel".
vowel = ["A" , "E" , "I" , "O" , "U"]
def e_silaba(word):
if word[0] in vogal or word[1] in vowel:
return True
elif word not in vowel:
return False
else:
print "e_word:invalid argument"
If you want to verify that the word in question IS a word just by checking to see if it contains vowels, use this for loop:
for letter in word:
if letter.upper() in vowel:
return True
return False
This will check every letter in your word (regardless of length) to see if it is in your list vowel. Also note that it checks letter.upper(), which converts the letter to its uppercase version to accurately compare it to your uppercase vowel list. If it reaches the end of the word without having returned True, it means it did not encounter any vowels and will then return false.
If you wish to check if word contains only alphabetic characters you can use the .isalpha() method on it. As far as your function is concerned maybe you can solve it using sets like below:
vowels = set('aeoiu')
def e_silaba(word):
if (set(word.lower()).issubset(vowels)):
return True
else:
return False
What it does is first lowercase all the letters in word with the .lower() method, makes a set out of all characters in the new lower-cased word and checks if those characters are subset of the vowels set with the .issubset() method.
You also perhaps don't even need to make this function and explicitly return True or False. You can simply use set(word.lower()).issubset(vowels) which itself is a boolean expression that will return True or False.
Just to put #Chris_Rands's excellent comment into an answer: The simplest way is to turn the list of vowels into a set and compare the letters in word.lower() against it using any():
vowels = set("aeiou")
def e_silaba(word):
return any(x in vowels for x in word.lower())
If you want to make sure the word is not entirely composed of vowels you can use this solution:
vowels = set("aeiou")
def e_silaba(word):
if all(x in vowels for x in word.lower()):
return False
else:
return any(x in vowels for x in word.lower())
This will exclude "a" and "i" which actually are words though. As one last example, if you only want to check that condition for words of at least two characters, use this:
vowels = set("aeiou")
def e_silaba(word):
if len(word) > 1 and all(x in vowels for x in word.lower()):
return False
else:
return any(x in vowels for x in word.lower())
Hopefully this is enough to illustrate how you could add more conditions.
Try this
vowel=['A','E','I','O','U']
def e_silaba(word):
word=word.upper()
for i in vowel:
try:
word.index(i)
return True
except ValueError:
continue
return False
Output will be
>>> e_silaba('sandeep')
True
>>> e_silaba('dp')
False
>>> e_silaba('lda')
True
>>> e_silaba('bcf')
False
>>>
This question already has answers here:
How to test multiple variables for equality against a single value?
(31 answers)
Closed 7 years ago.
I am new to programming, and am learning on Python 3.4. I am working on an exercise to determine if a user defined letter is a vowel or consonant.
My original if statement looked as follows:
letter = input('Enter a letter')
if letter == 'a' or 'e' or 'i' or 'u':
print('your letter is a vowel')
else:
print ('your letter is a consonant')
this returned that my letter was a vowel every time.
I have since learned the answer was to have an if statement that looks as follows:
if letter == 'a' or letter == 'i' or .......
My question is why did my original if statement return that it was a vowel every time, and not give me an error?
My though process is that it is verifying that it is a string.
Any non-zeroish value evaluates to True in a condition. Also, comparison operators (== in this case) have higher priority than logical operators (or,and,not). (Details: https://docs.python.org/3/library/stdtypes.html)
So python interpreted your if statement as:
if (letter == 'a') or ('e') or ('i') or ('u'):
Since 'e' is not zero or zero-like, that part of the if was true, so your expression was true.
An easier approach than your working solution is:
if letter in 'aeiou':
Which checks if letter is a character in the string.
I'm writing a program in which I can Reverse the sequence and Replace all As with Ts, all Cs with Gs, all Gs with Cs, and all Ts with As. the program is to read a sequence of bases and output the reverse complement sequence. I am having trouble to do it so can anyone please help me with this by having a look on my code:
word = raw_input("Enter sequence: ")
a = word.replace('A', 'T')
b = word.replace('C', 'G')
c = word.replace('G', 'C')
d = word.replace('T', 'A')
if a == word and b == word and c == word and d == word:
print "Reverse complement sequence: ", word
And I want this sort of output:
Enter sequence: CGGTGATGCAAGG
Reverse complement sequence: CCTTGCATCACCG
Regards
I would probably do something like:
word = raw_input("Enter sequence:")
# build a dictionary to know what letter to switch to
swap_dict = {'A': 'T', 'T': 'A', 'C': 'G', 'G': 'C'}
# find out what each letter in the reversed word maps to and then join them
newword = ''.join(swap_dict[letter] for letter in reversed(word))
print "Reverse complement sequence:", newword
I don't quite understand your if statement, but the above code avoids needing one by looping over each letter, deciding what it should become, and then combining the results. That way each letter only gets converted once.
Edit: oops, I didn't notice that you wanted to reverse the string too. Fixed.
Your code as written is problematic, because steps 1 and 4 are the opposite of each other. Thus they can't be done in completely separate steps: you convert all As to Ts, then convert those (plus the original Ts) to As in step 4.
For something simple, built-in, and- hopefully- efficient, I'd consider using translation tables from the string module:
import string
sequence = "ATGCAATCG"
trans_table = string.maketrans( "ATGC" , "TACG")
new_seq = string.translate( sequence.upper() , trans_table )
print new_seq
This gives the output desired:
'TACGTTAGC'
Although I doubt that your users will ever forget to capitalize all letters, it's good practice to ensure that the input is in the form expected; hence the use of sequence.upper(). Any letters/bases with conversions not included in the translation table will be unaffected:
>>> string.translate( "AEIOUTGC" , trans_table )
'TEIOUACG'
As for the reverse complement sequence? You can do that concisely using slice notation on the output string, with a step of -1:
>>> new_seq[::-1]
'CGATTGCAT'
So if I understand what you want to do, you want to swap all Ts and As as well as swap all Gs and Cs and you want to reverse the string.
OK, well first, let's work on reversing the string, something you don't have implemented. Unfortunately, there's no obvious way to do it but this SO question about how to reverse strings in python should give you some ideas. The best solution seems to be
reversedWord = word[::-1]
Next, you need to swap the letters. You can't call replace("T", "A") and replace("A","T") on the same string because that will make both you As and Ts all be set to T. You seem to have recognized this but you use separate strings for each swap and don't ever combine them. Instead you need to go through the string, one letter at a time and check. Something like this:
swappedWord = "" #start swapped word empty
for letter in word: #for every letter in word
if letter == "A": #if the letter is "A"
swappedWord += "T" #add a "T
elif letter == "T": #if it's "T"
swappedWord += "A" #add an "A"
elif letter == "C": #if it's "C"
... #you get the idea
else: #if it isn't one of the above letters
swappedWord += letter #add the letter unchanged
(EDIT - DSM's dictionary based solution is better than my solution. Our solutions are very similar though in that we both look at each character and decide what the swapped character should be but DSM's is much more compact. However, I still feel my solution is useful for helping you understand the general idea of what DSM's solution is doing. Instead of my big if statement, DSM uses a dictionary to quickly and simply return the proper letter. DSM also collapsed it into a single line.)
The reason why your if statement isn't working is that you're basically saying "if a, b, c, d, and word are all exactly the same" since == means "are equal" and if a is equal to word and b is equal to word then a must be equal to b. This can only be true if the string has no As, Ts, Cs, or Gs (i.e. word is unchanged by the swaps), so you never print out the output.