So I'm quite new to Python and am trying to create a program to identify 'super anagrams' i.e anagrams that have the same first and last letters. I came up with this, and it works, but I've got this feeling that there's a cleaner way to do it. Any ideas? Cheers.
words = input('Enter words: ')
listed = words.split()
first = listed[0]
second = listed[1]
first_split = (list(first))
second_split = (list(second))
if first_split[0]==second_split[0] and first_split[-1]==second_split[-1]:
first_split_alpha = sorted(first_split)
second_split_alpha = sorted(second_split)
if first_split_alpha == second_split_alpha:
print('Super Anagram!')
else: print('Huh?')
else: print('Huh?')
1) The temporary variable listed is unnecessary. Use tuple unpacking to get the values
2) The use of list is unnecessary. str is an iterable object, too.
3) The use of _alpha is unecessary. Just use sorted(foo) in your expression.
a,b = input('Enter words: ').split()
if sorted(a) == sorted(b) and a[0] == b[0] and a[-1] == b[-1]:
print('Super Anagram!')
else:
print('Huh?')
One suggestion I would make would be to check that the input contains exactly two words. Your code would throw an exception if the user were to enter just one word. You might do this by:
words = [] # empty list
while len(words) != 2:
words = input('Enter two words: ').split()
Following that, you could reduce the number of distinct variables you create. If you create a variable and then only use it once, chances are that you could inline whatever you are doing with that variable:
first = words[0]
second = words[1]
if (first[0] == second[0] and
first[-1] == second[-1] and
sorted(first) == sorted(second)):
print('Super Anagram!')
else:
print('Huh?')
Related
I intended to let the program check if the input matches with any character in a str and then print out the result, the player input and the underscores in the correct places. This is my test code so far:
astring = "apple"
bstring = "_ " * 5
print(bstring)
my_input = input("enter a letter")
for i, n in enumerate(astring):
if my_input == i:
bstring[n] = my_input
else:
i = i + 1
print(bstring)
However, only the underscores are being printed out. Can anyone help me?
In your loop, you should be checking to see if the letter at your current index of your string is the same as the letter at the current index of your input string, to do this you can use:
if i < len(my_input) and my_input[i] == n:
Also, strings in Python are immutable, and so you can't change them via index. Instead, use an array of _, so that you can change what is at a particular index. Then, at the end, join each element in your list by a space.
Lastly, there is no need to increment i, as this is done for you by your for loop:
astring='apple'
bstring=['_']*len(astring)
print(bstring)
my_input = input('enter a letter')
for i,n in enumerate(astring):
if i < len(my_input) and my_input[i] == n:
bstring[i] = n
print(' '.join(bstring))
for i,n in enumerate(astring):
'i' is the index, 'n' is the character. You have it the other way around in 'if'.
hope it will help you
astring='apple'
bstring=["_" for i in range(len(astring))]
print(bstring)
my_input=input('enter a letter')
for i,n in enumerate(astring):
if my_input==n:
bstring[i]=my_input
else:
i=i+1
print(*bstring)
I have to enter a string, remove all spaces and print the string without vowels. I also have to print a string of all the removed vowels.
I have gotten very close to this goal, but for some reason when I try to remove all the vowels it will not remove two vowels in a row. Why is this? Please give answers for this specific block of code, as solutions have helped me solve the challenge but not my specific problem
# first define our function
def disemvowel(words):
# separate the sentence into separate letters in a list
no_v = list(words.lower().replace(" ", ""))
print no_v
# create an empty list for all vowels
v = []
# assign the number 0 to a
a = 0
for l in no_v:
# if a letter in the list is a vowel:
if l == "a" or l == "e" or l == "i" or l == "o" or l == "u":
# add it to the vowel list
v.append(l)
#print v
# delete it from the original list with a
del no_v[a]
print no_v
# increment a by 1, in order to keep a's position in the list moving
else:
a += 1
# print both lists with all spaces removed, joined together
print "".join(no_v)
print "".join(v)
disemvowel(raw_input(""))
Mistakes
So there are a lot of other, and perhaps better approaches to solve this problem. But as you mentioned I just discuss your failures or what you can do better.
1. Make a list of input word
There are a lot of thins you could do better
no_v = list(words.lower().replace(" ", ""))
You don't replaces all spaces cause of " " -> " " so just use this instead
no_v = list(words.lower().translate( None, string.whitespace))
2. Replace for loop with while loop
Because if you delete an element of the list the for l in no_v: will go to the next position. But because of the deletion you need the same position, to remove all the vowels in no_v and put them in v.
while a < len(no_v):
l = no_v[a]
3. Return the values
Cause it's a function don't print the values just return them. In this case replace the print no_v print v and just return and print them.
return (no_v,v) # returning both lists as tuple
4. Not a mistake but be prepared for python 3.x
Just try to use always print("Have a nice day") instead of print "Have a nice day"
Your Algorithm without the mistakes
Your algorithm now looks like this
import string
def disemvowel(words):
no_v = list(words.lower().translate( None, string.whitespace))
v = []
a = 0
while a < len(no_v):
l = no_v[a]
if l == "a" or l == "e" or l == "i" or l == "o" or l == "u":
v.append(l)
del no_v[a]
else:
a += 1
return ("".join(no_v),"".join(v))
print(disemvowel("Stackoverflow is cool !"))
Output
For the sentence Stackoverflow is cool !\n it outputs
('stckvrflwscl!', 'aoeoioo')
How I would do this in python
Not asked but I give you a solution I would probably use. Cause it has something to do with string replacement, or matching I would just use regex.
def myDisemvowel(words):
words = words.lower().translate( None, string.whitespace)
nv = re.sub("[aeiou]*","", words)
v = re.sub("[^a^e^i^o^u]*","", words)
return (nv, v)
print(myDisemvowel("Stackoverflow is cool !\n"))
I use just a regular expression and for the nv string I just replace all voewls with and empty string. For the vowel string I just replace the group of all non vowels with an empty string. If you write this compact, you could solve this with 2 lines of code (Just returning the replacement)
Output
For the sentence Stackoverflow is cool !\n it outputs
('stckvrflwscl!', 'aoeoioo')
You are modifying no_v while iterating through it. It'd be a lot simpler just to make two new lists, one with vowels and one without.
Another option is to convert it to a while loop:
while a < len(no_v):
l = no_v[a]
This way you have just a single variable tracking your place in no_v instead of the two you currently have.
For educational purposes, this all can be made significantly less cumbersome.
def devowel(input_str, vowels="aeiou"):
filtered_chars = [char for char in input_str
if char.lower() not in vowels and not char.isspace()]
return ''.join(filtered_chars)
assert devowel('big BOOM') == 'bgBM'
To help you learn, do the following:
Define a function that returns True if a particular character has to be removed.
Using that function, loop through the characters of the input string and only leave eligible characters.
In the above, avoid using indexes and len(), instead iterate over characters, as in for char in input_str:.
Learn about list comprehensions.
(Bonus points:) Read about the filter function.
Okay, so I am stuck at this part in my code. When I want the letter that the user guesses to replace that letter in the string of underscores, it replaces every single letter with that letter. I don't know what to do. Here is the code.
def hangman(secret):
'''
'''
guessCount = 7
w = '_'*len(secret)
while guessCount > 0:
guess = input('Guess: ')
if guess in secret:
indices = indexes(secret, guess)
print(indices)
for i in range(len(indices)):
w = w.replace(w[indices[i]],secret[indices[i]])
print(w)
else:
guessCount = guessCount - 1
print('Incorrect.',guessCount,'incorrect guesses remaining.')
Any help in pointing out what I can do specifically in line 9 and 10 would be greatly appreciated.
Here is the first function that I defined earlier that I use in this function.
def indexes(word, letter):
'''returns a list of indexes at which character letter appears in word'
'''
indices = []
for i in range(len(word)):
if letter in word[i]:
indices.append(i)
return indices
Modify the loop to iterate through the contents of indices:
for i in indices:
w = w.replace(w[indices[i]],secret[indices[i]])
print(w)
Otherwise, the loop will execute from 0 to the length of the indices array since range was mentioned.
Also, you may probably want to move the print statement outside the for loop.
What is happening is that line 10 is thinking that you want to replace "_" with "guess". Instead:
for i in indices:
w = list(w)
w[i] = guess
w = ''.join(w)
print(w)
There is most likely a more elegant way of doing this rather than changing w from string to list and from list back to string again, but I can't think of it off the top of my head.
Strings are immutable in Python. Hence, it is not a suitable data structure for representing your word. In my opinion, Kyle Friedline's approach is probably the right way.
def hangman(secret, guessCount=7):
assert guessCount > 0 # Never really good to hard code magic numbers.
w = ['_'] * len(secret) # Make 'w' a list instead because list is mutable
while guessCount > 0:
guess = input("Guess: ")
if guess in secret:
indices = indexes(secret, guess) # I'm guessing indexes is defined elsewhere?
for i in indices:
w[i] = guess # Make it explicit. secret[i] == guess anyway.
print("".join(w)) # Join w into a word
else:
guessCount -= 1 # More concise
print("Incorrect. ", guessCount, " incorrect guesses remaining.")
A little suggestion for implementing indexes:
def indexes(word, letter):
return [i for i, c in enumerate(word) if c == letter]
Or simply replace the call to indexes() with:
indices = [i for i, c in enumerate(secret) if c == guess]
Where you have w[indices[i]] whatever the index number you use, w contains _ there. Because of that, you always do something like: w.replace('_', 'e') and:
>>> help("".replace)
Help on built-in function replace:
replace(...)
S.replace(old, new[, count]) -> string
Return a copy of string S with all occurrences of substring
old replaced by new.
So you get:
>>> "_____".replace('_', 'e')
'eeeee'
#Vaiska makes another good point, you are counting through the length of indices, not the indices themselves. So you are always counting 0,1,2,3...
#Kyle Friedline has one solution, another would be to build up a new string taking one character at a time, either from the guess or from the secret, depending on whether you were at an index point or not.
I've been working on this Palindrome program and am really close to completing it.Close to the point that it's driving me a bit crazy haha.
The program is supposed to check each 'phrase' to determine if it is a Palindrome or not and return a lowercase version with white space and punctuation removed if it is in fact a Palindrome. Otherwise, if not, it's supposed to return None.
I'm just having an issue with bringing my test data into the function. I can't seem to think of the correct way of dealing with it. It's probably pretty simple...Any ideas?
Thanks!
import string
def reverse(word):
newword = ''
letterflag = -1
for numoletter in word:
newword += word[letterflag]
letterflag -= 1
return newword
def Palindromize(phrase):
for punct in string.punctuation:
phrase= phrase.replace(punct,'')
phrase = str(phrase.lower())
firstindex = 0
secondindex = len(phrase) - 1
flag = 0
while firstindex != secondindex and firstindex < secondindex:
char1 = phrase[firstindex]
char2 = phrase[secondindex]
if char1 == char2:
flag += 1
else:
break
firstindex += 1
secondindex -= 1
if flag == len(phrase) // (2):
print phrase.strip()
else:
print None
def Main():
data = ['Murder for a jar of red rum',12321, 'nope', 'abcbA', 3443, 'what',
'Never odd or even', 'Rats live on no evil star']
for word in data:
word == word.split()
Palindromize(word)
if __name__ == '__main__':
Main()
Maybe this line is causing the problems.
for word in data:
word == word.split() # This line.
Palindromize(word)
You're testing for equality here, rather than reassigning the variable word which can be done using word = word.split(). word then becomes a list, and you might want to iterate over the list using
for elem in word:
Palindromize(elem)
Also, you seem to be calling the split method on int, which is not possible, try converting them to strings.
Also, why do you convert the phrase to lower case in the for loop, just doing it once will suffice.
At the "core" of your program, you could do much better in Python, using filter for example. Here is a quick demonstration:
>>> phrase = 'Murder for a jar of red rum!'
>>> normalized = filter(str.isalnum, phrase.lower())
>>> normalized
'murderforajarofredrum'
>>> reversed = normalized[-1::-1]
>>> reversed
'murderforajarofredrum'
# Test is it is a palindrome
>>> reversed == normalized
True
Before you go bananas, let's rethink the problem:
You have already pointed out that Palindromes only make sense in strings without punctuation, whitespace, or mixed case. Thus, you need to convert your input string, either by removing the unwanted characters or by picking the allowed ones. For the latter, one can imagine:
import string
clean_data = [ch for ch in original_data if ch in string.ascii_letters]
clean_data = ''.join(clean_data).lower()
Having the cleaned version of the input, one might consider the third parameter in slicing of strings, particularly when it's -1 ;)
Does a comparison like
if clean_data[::-1] == clean_data:
....
ring a bell?
One of the primary errors that i spotted is here:
for word in data:
word==word.split()
Here, there are two mistakes:
1. Double equals make no point here.
2. If you wish to split the contents of each iteration of data, then doing like this doesn't change the original list, since you are modifying the duplicate set called word. To achieve your list, do:
for i in range(data):
data[i]=data[i].split()
This may clear your errors
query level: beginner
As part of a learning exercise I have written code that must check if a string (as it is build up through raw_input) matches the beginning of any list item and if it equals any list item.
wordlist = ['hello', 'bye']
handlist = []
letter = raw_input('enter letter: ')
handlist.append(letter)
hand = "".join(handlist)
for item in wordlist:
if item.startswith(hand):
while item.startswith(hand):
if hand not in wordlist:
letter = raw_input('enter letter: ')
handlist.append(letter)
hand = "".join(handlist)
else: break
else: break
print 'you loose'
This code works but how can my code (and my reasoning/approach) be improved?
I have the feeling that my nesting of IF, WHILE and FOR statements is overkill.
EDIT
Thanks to Dave, I was able to considerably shorten and optimise my code.
wordlist = ['hello','hamburger', 'bye', 'cello']
hand = ''
while any(item.startswith(hand) for item in wordlist):
if hand not in wordlist:
hand += raw_input('enter letter: ')
else: break
print 'you loose'
I'm surprised my original code worked at all...
Firstly, you don't need the handlist variable; you can just concatenate the value of raw_input with hand.
You can save the first raw_input by starting the while loop with hand as an empty string since every string has startswith("") as True.
Finally, we need work out best way to see if any of the items in wordlist starts with hand. We could use a list comprehension for this:
[item for item in wordlist if item.startswith(hand)]
and then check the length of the returned list if greater than zero.
However, even better, python has the any() function which is perfect for this: it returns True if any element of an iterable is True, so we just evaluate startswith() for each member of wordlist.
Putting this all together we get:
wordlist = ['hello', 'bye']
hand = ""
while any(item.startswith(hand) for item in wordlist):
hand += raw_input('enter letter: ')
print 'you loose'