Creating an anagram checker - python

So I have been able to create the following program which compares two strings to see if they are anagrams of each other.
def anagrams( string1, string2 ):
if sorted(string1.lower()) == sorted(string2.lower()):
return True
else:
return False
However, my issue is that I wish to not return a True value should both input strings be the exact same. For example:
anagrams('silent','silent')
This outputs True but I do not want it to do that, what changes should I make to implement this?

Just check if the strings are different:
def anagrams(string1, string2):
if sorted(string1.lower()) == sorted(string2.lower()) and string1.lower() != string2.lower():
return True
else:
return False
result = anagrams('silent', 'silent')
print(result)
Output
False
You could use Counter instead of sorted:
from collections import Counter
def anagrams(string1, string2):
if string1.lower() != string2.lower() and Counter(string1.lower()) == Counter(string2.lower()):
return True
else:
return False
print(anagrams('silent', 'silent'))
print(anagrams('silent', 'sitlen'))
Output
False
True
UPDATE
As suggested by #RoadRunner, you could do:
from collections import Counter
def anagrams(string1, string2):
ls1, ls2 = string1.lower(), string2.lower()
return ls1 != ls2 and Counter(ls1) == Counter(ls2)
print(anagrams('silent', 'silent'))
print(anagrams('silent', 'sitlen'))

def anagrams( string1, string2 ):
if sorted(string1.lower()) == sorted(string2.lower()) and string1.lower() != string2.lower():
return True
else:
return False
print(anagrams('silent','silent'))

Related

CS50P PSETS 2, Vanity plates

I'm having some issues with the psets 2 of cs50p, precisely I'm talking about the "Vanity Plates" problem, where I fulfilled all requests except one, which said:
“Numbers cannot be used in the middle of a plate; they must come at the end. For example, AAA222 would be an acceptable … vanity plate; AAA22A would not be acceptable. The first number used cannot be a ‘0’.” Can you help me? Thank's
this is the code I wrote so far:
def main():
plate = input("Plate: ")
if is_valid(plate):
print("Valid")
else:
print("Invalid")
def is_valid(s):
if s.isalnum() | s[:2].isalpha() | 2 < len(s) < 6 | :
else:
return False
main()
you have to consider all the cases one by one, this is how I solved it:
def main():
plate = input("Plate: ")
if is_valid(plate):
print("Valid")
else:
print("Invalid")
def is_valid(s):
if len(s) < 2 or len(s) > 6:
return False
elif not s[0].isalpha() or not s[1].isalpha():
return False
elif checkFirstZero(s):
return False
elif checkMiddleZero(s):
return False
elif last(s):
return False
elif worng(s):
return False
return True
def last(s):
isAlp = False
isNum = False
for w in s:
if not w.isalpha():
isNum = True
else:
if isNum:
return True
return False
def checkCuntuNNumber(s):
isFirstTry = True
isNum = False
for w in s:
if not w.isalpha():
if isFirstTry:
isNum = True
isFirstTry = False
if isNum and s[-1].isalpha():
return True
def checkMiddleZero(s):
isFirstTry = True
isNum = False
for w in s:
if not w.isalpha():
if isFirstTry:
isNum = True
isFirstTry = False
if isNum and s[-1].isalpha():
return True
else:
return False
def checkFirstZero(s):
for w in s:
if not w.isalpha():
if int(w) == 0:
return True
else:
return False
def worng(s):
for w in s:
if w in [" ", ".", ","]:
return True
return False
main()
This is how I did it. I am sure there is an easier way to do it out there but hopefully this helps :)
characters = ['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']
numbers = ['1','2','3','4','5','6','7','8','9','0']
def main ():
plate = (input ("Plate: ")).upper()
if is_valid(plate):
print ('Valid')
else:
print ('Invalid')
def is_valid (s):
#Check whether length is between 2 and 6 included
if len(s) < 2 or len(s) > 6:
return False
elif char_check(s):
return False
elif char_start(s):
return False
elif zero_check(s):
return False
elif alpha_follow_check (s):
return False
else:
return True
#Check for valid characters
def char_check(s):
for i in s:
if not (i in characters or i in numbers):
return True
#Check whether first two are letters
def char_start (s):
for i in s[:2]:
if not i in characters:
return True
#Check if zero is first number listed
def zero_check (plate_response):
length_string = len (plate_response)
letter_position = 0
number_present = 0
zero_position = None
if any (i in numbers for i in plate_response):
for i in plate_response [0:length_string]:
if i == '0':
zero_position = letter_position
break
letter_position = letter_position + 1
for i in plate_response [0:zero_position]:
if i in numbers:
number_present = 1
if number_present == 0:
return True
else:
return False
#Check alphabet follows numbers
def alpha_follow_check (plate_response):
length_string = len (plate_response)
letter_position = 0
number_position = None
if any (i in numbers for i in plate_response):
for i in plate_response [0:length_string]:
if i in numbers:
number_position = letter_position
break
letter_position = letter_position + 1
for i in plate_response [number_position:length_string]:
if i in characters:
return True
else:
return False
main ()
idk if will help, but the part that i've had the most difficulty in this problem was: "Numbers cannot be used in the middle of a plate; they must come at the end, AAA22A would not be acceptable", then i learned that you can create a full list from the plate that the user inputed, and how to actually use it, with the:
ls = list(s)
for i in range(len(ls)):
After that, we check when the first number appears. "if == '0'" ,then returns False to the function.
After that, if the first number isn't a 0, the program checks if the next item in that list is letter, and, if it is, also return False.
i < len(ls) -1 => this part guarantee that the program will not run in the last item of the list
ls[i+1].isalpha() => and this part check that, if the item on the list was a number, and then the next item is a letter, it returns False
I hope it helps someone, i've spend a lot of time trying to figure it out what to do, and then reached this solution: "for i in range(len(ls))".
Now my code is complete and working.
My code:
def main():
plate = input("Plate: ")
if is_valid(plate):
print("Valid")
else:
print("Invalid")
def is_valid(s):
if not s.isalnum():
return False
elif len(s) < 4 or len(s) > 7:
return False
elif s[0].isdigit()or s[1].isdigit():
return False
elif s[-1].isalpha() or s[-2].isalpha():
return False
else:
ls = list(s)
for i in range(len(ls)):
if ls[i].isdigit():
if ls[i] == '0':
return False
elif i < len(ls) -1 and ls[i+1].isalpha():
return False
else:
return True
main()

nested if python executed in one case but not in another similar condition

Hi please find my code below:
def isIn(char, aStr):
#char: a single character
#aStr: an alphabetized string
#returns: True if char is in aStr; False otherwise
length=len(aStr)
print(length, aStr) #check
if length == 0:
return False
elif length == 1:
if char == aStr:
return True
else:
return False
elif char==aStr[int(length/2)]:
return True
elif char<aStr[int(length/2)]:
print("checked")
aStr=aStr[0:int(length/2)]
isIn(char,aStr)
elif char>aStr[int(length/2)]:
isIn(char,aStr[int(length/2):-1])
if i run with
a='b'
s='b'
v=isIn(a,s)
print(v)
prints out True at the last line
if i run with
a='b'
s='bcd'
v=isIn(a,s)
print(v)
prints out None when it should print True. Any ideas?
you don't need to write a lot of code, you can just do:
def isIn(char, aStr):
return char in aStr
the 'in' keyword will return True if char is in aStr and False otherwise

trying to do a python for code without using the "in" operator and it's not working

Simple assignment from uni, supposed to find a word in a list and print if true without using the "in" operator. I've instead used = and it's just not printing anything. Is there something wrong with the code or is there an alternative I'm missing?
wordlist = ["hi", "many","way","photo","mobile"]
def word_in_list_for(words,word):
for word = wordlist:
if word == wordlist:
return True
else:
continue
print(word_in_list_for(wordlist,"bild"))
def word_in_wordlist(words, word):
i = 0
while i < len(words):
if words[i] == word:
return True
i += 1
return False
Testing:
In [221]: wordlist = ["hi", "many","way","photo","mobile"]
In [222]: print(word_in_wordlist(wordlist,"bild"))
False
In [223]: print(word_in_wordlist(wordlist,"photo"))
True
Do this:
wordlist = ["hi", "many","way","photo","mobile"]
def word_in_list_for(words,word):
i = 0
while wordlist[i]:
if word == wordlist[i]:
return True
else:
i += 1
print(word_in_list_for(wordlist,"bild"))
Tell me if this works
You can use set
wordlist = ["hi", "many","way","photo","mobile"]
def word_in_list_for(words,word):
words_set = set(words)
return {word}.issubset(words_set)
print(word_in_list_for(wordlist,"bild"))
False
You should use the indexing. I have written an working example from your code. You can find the explanation as comments in script.
Code:
wordlist = ["hi", "many", "way", "photo", "mobile"]
def word_in_list_for(words, word):
for index in range(len(words)): # Get the indexes of your list.
if word == words[index]: # If the value of the index is the same as word
return True # Return True
return False # The the elem is not is the list return False
print(word_in_list_for(wordlist, "bild"))
Successful test (word_in_list_for(wordlist, "mobile")) :
>>> python3 test.py
True
Unsuccessful test (word_in_list_for(wordlist, "bild")) :
>>> python3 test.py
False

def function producing incorrect output

My task is to:
Write a function, starts_with(word, chs) that returns whether or not the string word begins with one of the characters in the list chs.
If word is an empty string, return False.
If chs is an empty list, return False.
I'm passing 6/7 test cases except for one which shows an Assertion error, however, I don't know what input is being used in each test case so I can't figure out the issue. What could the issue be?
def starts_with(word, chs):
x = 0
if (len(chs)== 0) or (word == ""):
return (False)
while x < len(chs):
s = word[0]
if s == chs[x]: {
}
x += 1
return (True)
word = ()
chs = ()
Try approaching this task using the proper Python builtin functions rather than apply C/Java-style programming. It is way more readable.
Using string.startswith():
def starts_with(word, chs):
for c in chs:
if word.startswith(c):
return True
return False #you can avoid this line, it will return None by default
Another way would be to check if the first letter of word is in chs:
def f(word, chs):
if word and chs and word[0] in chs:
return True
return False
Try this:
def starts_with(word, chs):
if (len(chs)== 0) or (word == ""):
return False
elif word[0] in chs:
return True
an update:
def starts_with(word, chs):
if not word: return False
elif word[0] in chs:
return True

Find all letters of a string in another string

I'm working on a project that find all anagrams of a word with many others words.
For that I need a function that takes 2 strings and return True if all letters of str1 are in str2.
I made this code:
def almost_anagram(str1, str2):
tmp = list(str2)
for i in str1:
if i in tmp:
tmp.remove(i)
else:
return False
return True
For exemple:
almost_anagram("OLLE", "HELLO") = True
almost_anagram("OOLE", "HELLO") = False
But is there a better/faster way to do that ?
You can use Counter, which essentially represents a multi-set:
import collections
def almost_anagram(word1, word2):
counter1 = collections.Counter(word1)
counter2 = collections.Counter(word2)
return counter1 - counter2 == {}
# alternatively:
# return all(counter2[k] >= v for k, v in counter1.items())
# return counter1 & counter2 == counter1
The code could be simplified to return counter1 < counter2 if Counter supported subset-testing with < like sets do, but unfortunately it doesn't.
Output:
>>> almost_anagram("OLLE", "HELLO")
True
>>> almost_anagram("OOLE", "HELLO")
False
With collections.Counter object to get letter counts at once:
import collections
def almost_anagram(str1, str2):
str1_cnt, str2_cnt = collections.Counter(str1), collections.Counter(str2)
return all(k in str2_cnt and str2_cnt[k] == v
for k,v in str1_cnt.items())
Test:
print(almost_anagram("OLLE", "HELLO")) # True
print(almost_anagram("OOLE", "HELLO")) # False
Using a list comprehension with all should be faster.
Ex:
def almost_anagram(str1, str2):
return all(str2.count(i) >= str1.count(i) for i in set(str1))
print(almost_anagram("OLLE", "HELLO"))
print(almost_anagram("OOLE", "HELLO"))
Output:
True
False
i prefer using count() function and by the way you don't need to convert the string into list:
def almost_anagram(str1, str2):
for i in str1:
if(str1.count(i)==str2.count(i)):
pass
else:
return False
return True
print(almost_anagram('olle','hello'))
print(almost_anagram('oole','hello'))
output:
True
False

Categories

Resources