Python: testing inter-dependence between strings - python

I have a piece of code which compares two strings.
If they are both empty (i.e. ""), the code should return True
If they are both 'populated', the code should return True
otherwise (i.e. one is empty), the code should return False
Currently I have:
def compare(first, second):
if first:
return bool(second)
elif second:
return bool(first)
else:
return True
I'm sure there is a more succinct way to do this with fewer clauses (or ideally no clauses)?

You want the inverse of "exclusive or":
>>> def compare(first, second):
return not bool(first) ^ bool(second)
>>> compare("", "")
True
>>> compare("foo", "")
False
>>> compare("", "bar")
False
>>> compare("foo", "bar")
True

return len(first) == len(second) == 0 or len(first) > 0 and len(second) > 0
Or
return a==b=='' or a!='' and b!=''
You shouldn't count on boolean operators on strings

Related

How can I write a function that verifies if a list is a non-contiguous sublist of another list, in python? [duplicate]

If I have string needle and I want to check if it exists contiguously as a substring in haystack, I can use:
if needle in haystack:
...
What can I use in the case of a non-continuous subsequence? Example:
>>> haystack = "abcde12345"
>>> needle1 = "ace13"
>>> needle2 = "123abc"
>>> is_subsequence(needle1, haystack)
True
>>> is_subsequence(needle2, haystack) # order is important!
False
I don't know if there's builtin function, but it is rather simple to do manually
def exists(a, b):
"""checks if b exists in a as a subsequence"""
pos = 0
for ch in a:
if pos < len(b) and ch == b[pos]:
pos += 1
return pos == len(b)
>>> exists("moo", "mo")
True
>>> exists("moo", "oo")
True
>>> exists("moo", "ooo")
False
>>> exists("haystack", "hack")
True
>>> exists("haystack", "hach")
False
>>>
Using an iterator trick:
it = iter(haystack)
all(x in it for x in needle)
This is only a concise version of the same idea presented in tobias_k's answer.
Another possibility: You can create iterators for both, needle and haystack, and then pop elements from the haystack-iterator until either all the characters in the needle are found, or the iterator is exhausted.
def is_in(needle, haystack):
try:
iterator = iter(haystack)
for char in needle:
while next(iterator) != char:
pass
return True
except StopIteration:
return False
We can try simple for loop and break method and pass on substring once the match is found
def substr(lstr,sstr):
lenl = len(lstr)
for i in sstr:
for j in range(lenl):
if i not in lstr:
return False
elif i == lstr[j]:
lstr = lstr[j+1:]
break
else:
pass
return True

Palindrome check with recursive function without slicing and loops

I have an assignment, I have to make a python code that checks whether a string is a palindrome using a recursive function that returns a boolean, but I am not allowed to use reversed slicing nor loops, and I am not allowed to change the function format, here's my code but it returns True all the time
def is_palindrome(s):
res = []
s = ['']
if len(s) < 2:
return True
else:
rev_s = is_palindrome(s[1:]) + s[0]
res.append(rev_s)
if res == s:
return True
return False
You can check if the first and the last character of the given string are the same and then recursively check if the remaining string is a palindrome instead:
def is_palindrome(s):
return len(s) < 2 or s[0] == s[-1] and is_palindrome(s[1:-1])
I'm not sure if this counts as 'changing the function format', but here's my stab at a recursive version without slices:
def is_palindrome(s):
def is_palindrome_r(i, j):
if j <= i:
return True
if s[i] != s[j]:
return False
return is_palindrome_r(i + 1, j - 1)
return is_palindrome_r(0, len(s) - 1)
The inner function, is_palindrome_r, is the recursive function that takes two indexes, i and j. The last line sets the initial positions for these two indexes at 0 (the start of the string) and len(s) - 1 (the end of the string) and proceeds with the recursive logic. The recursive function has two exit conditions:
if j <= i we've reached the center of our palindrome. If we've gotten this far, we know all the other pairs of characters match and we don't need to do any more comparisons.
if the two characters pointed to by i and j do not match, it's definitely not a palindrome and we don't need to do any more comparisons.
Otherwise we don't yet know if the sequence is fully palindromic, so we we move our indexes one step inward (i + 1, j - 1) and go back to step 1.
No slicing used, just maintain the indices through the recursive calls
def is_palindrome(s):
return helper(s, 0, len(s)-1)
def helper(s, i, j):
if (i >= j):
return True
return s[i] == s[j] and helper(s, i+1, j-1)
If the mentioned function signature def is_palindrome(s) is the signature given by your teacher then no issue and there is no need to pass any extra parameter to achieve the goal.
Your teacher (or the one gave you this task is awesome) just wanted t check how do you handle this with only 1 parameter.
The concept is very simple, just change the type of argument (to list with 3 values) in second recursive call.
def is_palindrome(s):
if type(s) is str:
l = len(s)
if l == 0 or l == 1:
return True
else:
return is_palindrome([s, 0, -1])
else:
string, start, end = s # s is list here
if string[start] != string[end]:
return False
else:
if(start + 1 >= end - 1):
return True
return is_palindrome([s, start + 1, end - 1])
def main():
string1 = "abcba"
string2 = "abcde"
string3 = "AxxA"
print(is_palindrome(string1)) # True
print(is_palindrome(string2)) # False
print(is_palindrome(string3)) # True
main();
The following is not what you're looking for but may be you'll be looking for that in future.
>>> def is_palindrome(s):
... if s == "".join(reversed(s)):
... return True
... else:
... return False
...
>>> is_palindrome("ABA")
True
>>>
>>> is_palindrome("ABC")
False
>>>
>>> is_palindrome("XXZZXX")
True
>>>
>>> is_palindrome("##7")
False
>>>
>>> is_palindrome("1###1")
True
>>>
Thank you.

How can I return false if more than one number while ignoring "0"'s?

This is a function in a greater a program that solves a sudoku puzzle. At this point, I would like the function to return false if there is more then 1 occurrence of a number unless the number is zero. What do am I missing to achieve this?
L is a list of numbers
l =[1,0,0,2,3,0,0,8,0]
def alldifferent1D(l):
for i in range(len(l)):
if l.count(l[i])>1 and l[i] != 0: #does this do it?
return False
return True
Assuming the list is length 9, you can ignore the inefficiency of using count here (Using a helper datastructure - Counter etc probably takes longer than running .count() a few times). You can write the expression to say they are all different more naturally as:
def alldifferent1D(L):
return all(L.count(x) <= 1 for x in L if x != 0)
This also saves calling count() for all the 0's
>>> from collections import counter
>>> def all_different(xs):
... return len(set(Counter(filter(None, xs)).values()) - set([1])) == 0
Tests:
>>> all_different([])
True
>>> all_different([0,0,0])
True
>>> all_different([0,0,1,2,3])
True
>>> all_different([1])
True
>>> all_different([1,2])
True
>>> all_different([0,2,0,1,2,3])
False
>>> all_different([2,2])
False
>>> all_different([1,2,3,2,2,3])
False
So we can break this down into two problems:
Getting rid of the zeros, since we don't care about them.
Checking if there are any duplicate numbers.
Striping the zeros is easy enough:
filter(lambda a: a != 0, x)
And we can check for differences in a set (which has only one of each element) and a list
if len(x) == len(set(x)):
return True
return False
Making these into functions we have:
def remove_zeros(x):
return filter(lambda a: a != 0, x)
def duplicates(x):
if len(x) == len(set(x)):
return True
return False
def alldifferent1D(x):
return duplicates(remove_zeros(x))
One way to avoid searching for every entry in every position is to:
flags = (len(l)+1)*[False];
for cell in l:
if cell>0:
if flags[cell]:
return False
flags[cell] = True
return True
The flags list has a True at index k if the value k has been seen before in the list.
I'm sure you could speed this up with list comprehension and an all() or any() test, but this worked well enough for me.
PS: The first intro didn't survive my edit, but this is from a Sudoku solver I wrote years ago. (Python 2.4 or 2.5 iirc)

Finding anagrams in Python

I solved this problem the following way in Python:
s1,s2 = raw_input().split()
set1 = set(s1)
set2 = set(s2)
diff = len(set1.intersection(s2))
if(diff == 0)
print "Anagram!"
else:
print "Not Anagram!"
It seemed fine to me. But my professor's program said I'm missing some edge cases. Can you think of any edge cases I might have missed?
The correct way to solve this would be to count the number of characters in both the strings and comparing each of them to see if all the characters are the same and their counts are the same.
Python has a collections.Counter to do this job for you. So, you can simply do
from collections import Counter
if Counter(s1) == Counter(s2):
print "Anagram!"
else:
print "Not Anagram!"
If you don't want to use Counter, you can roll your own version of it, with normal dictionaries and then compare them.
def get_frequency(input_string):
result = {}
for char in input_string:
result[char] = result.get(char, 0) + 1
return result
if get_frequency(s1) == get_frequency(s2):
print "Anagram!"
else:
print "Not Anagram!"
use sorted :
>>> def using_sorted(s1,s2):
... return sorted(s1)==sorted(s2)
...
>>> using_sorted("hello","llho")
False
>>> using_sorted("hello","llhoe")
True
you can also use count:
>>> def using_count(s1,s2):
... if len(s1)==len(s2):
... for x in s1:
... if s1.count(x)!=s2.count(x):
... return False
... return True
... else: return False
...
>>> using_count("abb","ab")
False
>>> using_count("abb","bab")
True
>>> using_count("hello","llohe")
True
>>> using_count("hello","llohe")
sorted solution runs in O(n lg n) complexity and the count solution runs in O(n ^ 2) complexity, whereas the Counter solution in runs in O(N).
Note collections.Counter is better to use
check #fourtheye solution
Another way without sorting considering all are alphabets:
>>> def anagram(s1, s2):
... return sum([ord(x)**2 for x in s1]) == sum([ord(x)**2 for x in s2])
...
>>> anagram('ark', 'day')
False
>>> anagram('abcdef', 'bdefa')
False
>>> anagram('abcdef', 'bcdefa')
True
>>>
Don't do it with set Theory:
Code:
a='aaab'
b='aab'
def anagram(a,b):
setA=list(a)
setB=list(b)
print setA, setB
if len(setA) !=len(setB):
print "no anagram"
diff1 =''.join(sorted(setA))
diff2= ''.join(sorted(setB))
if (diff1 == diff2 ):
print "matched"
else:
print "Mismatched"
anagram(a,b)
the anagram check with two strings
def anagrams (s1, s2):
# the sorted strings are checked
if(sorted(s1.lower())== sorted(s2.lower())):
return True
else:
return False
check anagram in one liner
def anagram_checker(str1, str2):
"""
Check if the input strings are anagrams of each other
Args:
str1(string),str2(string): Strings to be checked
Returns:
bool: Indicates whether strings are anagrams
"""
return sorted(str1.replace(" ", "").lower()) == sorted(str2.replace(" ", "").lower())
print(anagram_checker(" XYZ","z y x"))

Processing a list to return true/false values using a for loop - Python

I have written this function trying to get it to return true or false in terms of the following condition, however I get this result when testing it:
>>> has_gt([2,3,4], 2)
False
def has_gt(nums, n):
"""Return True iff nums contains at least one number bigger than n.
has_gt(list<number>, number) -> boolean
"""
for i in (nums, n):
if i in nums > n:
return True
else:
return False
def has_gt(myList, value):
return any(i > value for i in myList)
>>> has_gt([2,3,4], 3)
True
>>> has_gt([1,2,3], 7)
False
Using a for loop
def has_gt(myList, value):
for i in myList:
if i > value:
return True
return False

Categories