Write a function repfree(s) that takes as input a string s and checks whether any character appears more than once. The function should return True if there are no repetitions and False otherwise.
I have tried this but I don't feel this is an efficient way of solving it. Can you suggest an efficient code for this, thanks?
def repfree(s):
newlist = []
for i in range(0, len(s)):
newlist.append(s[i])
newlist2 = set(newlist)
if len(newlist) == len(newlist2):
print("True")
else:
print("False")
One easy way to meet this requirement is to use regular expressions. You may not be allowed to use them, but if you can, then consider this:
def repfree(s):
if re.search(r'^.*(.).*\1.*$', s):
print("True")
else:
print("False")
Believe it or not, this problem can be solved in O(1) time, because every sufficiently large string contains at least one duplicate character. There are only a finite number of different Unicode characters, after all, so a string cannot be arbitrarily long while also using each Unicode character at most once.
For example, if you happen to know that your strings are formed of only lowercase letters, you can do this:
def has_repeated_char(s):
return len(s) > 26 or len(s) != len(set(s))
Otherwise you can replace the 26 with whatever number of characters your string could possibly contain; e.g. 62 for upper- and lowercase letters and digits.
As of February 2020, the whole of Unicode has 137,994 distinct characters (Wikipedia), so if your string length is 150,000 then you can return True without searching.
Try
chars = 'abcdefghijklmnopqrstuvwxyz'
def repfree(s):
for char in chars:
count = s.count(char)
if count > 1:
return False
return True
But, this is a long way as it scans the list 26 times. A much better and Pythonic way would be
import collections
def repfree(s):
results = collections.Counter(s)
for i in results:
if results[i] > 1:
return False
return True
Here, results is a dictionary that contains all the characters of s as key, and their respective frequency as value. Further, it is checked if any value is greater than 1, repetition has occurred.
You could split the string characters to a set and compare the length
def repfree(s):
se = set(string)
print(len(se) == len(s))
You can make your approach more efficient by removing the for loop.
len(s) == len(set(s))
Otherwise, try using any
any(s.count(c) > 1 for c in s)
You could do this way:
Method 1:
def repfree(s):
if len(set(s)) == len(s):
return True
return False
Method 2:
def repfree(s):
return len(set(s)) == len(s)
Why set?
set will return the list of all unique characters in the string in sorted order
Example :
set('shubham')
Output:
{'a', 'b', 'h', 'm', 's', 'u'}
So,if a character in a string appears more than once,it will not be equal to the length of string itself.
def repfree(str):
l=list(str)
for i in range(len(l)):
check=str.count(l[i])
if check>1:
flag=1
else:
flag=0
if(flag==1):
return False
else:
return True
def matched(s):
stack = []
for char in s:
if char == '(':
stack.append(char)
elif char == ')':
if not stack:
return False
stack.pop()
return not stack
Related
I am trying to solve the following problem:
Given a string str, the task is to check if the string is a valid
identifier or not. In order to qualify as a valid identifier,
the string must satisfy the following conditions:
It must start with either underscore(_) or any of the
characters from the ranges [‘a’, ‘z’] and [‘A’, ‘Z’].
There must not be any white space in the string.
And, all the subsequent characters after the first character
must not consist of any special characters like $, #, % etc.
Examples:
Input: str= “_code123”
Output: Valid
Input: str = “123code_”
Output: Invalid
My attempted solution, which works:
def isValid(str1, n):
# If first character is invalid
if (((ord(str1[0]) >= ord('a') and
ord(str1[0]) <= ord('z')) or
(ord(str1[0]) >= ord('A') and
ord(str1[0]) <= ord('Z')) or
ord(str1[0]) == ord('_')) == False):
return False
# Traverse the string for the rest of the characters
for i in range(1, len(str1)):
if (((ord(str1[i]) >= ord('a') and
ord(str1[i]) <= ord('z')) or
(ord(str1[i]) >= ord('A') and
ord(str1[i]) <= ord('Z')) or
(ord(str1[i]) >= ord('0') and
ord(str1[i]) <= ord('9')) or
ord(str1[i]) == ord('_')) == False):
return False
# is a valid identifier
return True
# Driver code
str1 = "_code123"
n = len(str1)
if (isValid(str1, n)):
print("Valid")
else:
print("Invalid")
How can I make the above code follow OOP principles, without so many nested ifs?
Have some read on regex it will help a lot for this kind of problem.
https://regexr.com/
This site is great for practice
import re
def isValid(str1):
res=re.match(r'^[_A-Za-z]\w+$',str1)
return res
str1 = "_code123"
n = len(str1)
if (isValid(str1)):
print("Valid")
else:
print("Invalid")
I think you can use that code.
if re.match('^[a-zA-Z_]+', line) is not None and re.match('^[\w-]+$', line) is not None:
return True
[a-zA-Z_]+ Your string may start with a-z, A-Z and underscore
There is nothing to say that nested ifs break OOP principles.
On the other hand, Python has certain features to help you out. First, you don't need to use ord so much because comparing two one-character strings does the same thing:
ord('a') < ord('b')
is equivalent to
'a' < 'b'
Second, Python allows you to chain math comparison operators, so instead of
'a' < 'b' and 'b' < 'c''
you can just type
'a' < 'b' < 'c'
But there is still an easier way: using the isalpha and isalphanumeric methods, you can avoid using the comparison operators, converting your code to:
Also, Python allows you to work directly on each character while looping by using the for c in str construct, saving you much indexing.
A more natural implementation of your code would be:
def is_valid(str1, n):
if not (str1[0] == '_' or str1[0].isalpha()):
return False
for c in str1[1:]:
if not (c == '_' or c.isalnum()):
return False
return True
You could even use a list comprehension for the second part, by doing:
if not all(c == '_' or c.isalnum() for c in str1[1:]):
return False
i am adding str[1] that is causing one repeated element to be left but if donot do that string does not get printed. any solutions
def removeCD(str):
l = len(str)
if l == 0 or l == 1:
return str
if(str[0]==str[1]):
return str[1] + removeCD(str[2:])
else:
return str[0] + removeCD(str[1:])
string = input().strip()
print(removeCD(string))
When characters are equal, you again adding duplicate character. This should work:
def removeCD(str):
l = len(str)
if l == 0 or l == 1:
return str
if(str[0]==str[1]):
return removeCD(str[1:])
else:
return str[0] + removeCD(str[1:])
string = input().strip()
print(removeCD(string))
Here is the case analysis we need to perform -
If string length is less than two (base case), there is nothing to compare, simply return the string
Otherwise (by induction) the string is at least two characters long. If the first matches the second, drop the first letter and return the recursive result
Otherwise (by induction) the string is at least two characters long and the first two characters do not match. Return the first char combined with the recursive result.
This encodes to a python program in a straightforward way -
def remove_adjacent_dupes (s = ""):
if len(s) < 2:
return s
elif s[0] == s[1]:
return remove_adjacent_dupes(s[1:])
else:
return s[0] + remove_adjacent_dupes(s[1:])
print(remove_adjacent_dupes("bookkeeper"))
# bokeper
When the characters are equal, you should be recursing on everything but the first character:
if(str[0]==str[1]):
return removeCD(str[1:])
def remove(string):
l = len(string)
if l==0 or l==1:
return string
if string[0] == string[1]:
s = remove(string[1:])
return s
else:
s = remove(string[1:])
return string[0]+s
string = input().strip()
print(remove(string))
I am creating a function that takes in a string and returns a matching string where every even letter is uppercase and every odd letter is lowercase. The string only contains letters
I tried a for loop that loops through the length of the string with an if statement that checks if the index is even to return an upper letter of that index and if the index is odd to return a lowercase of that index.
def my_func(st):
for index in range(len(st)):
if index % 2 == 0:
return st.upper()
else:
return st.lower()
I expected to have even letters capitalize and odd letter lowercase but I only get uppercase for the whole string.
Some issues in your code:
Currently you are returning from the function on the first index itself, i.e index=0 when you do return st.lower(), so the function will stop executing after it encounters the first index and breaks out of the for loop
Doing st.lower() or st.upper() ends up uppercasing/lowercasing the whole string, instead you want to uppercase/lowercase individual characters
One approach will be to loop over the string, collect all modified characters in a list, convert that list to a string via str.join and then return the result at the end
You also want to refer to each individual characters via the index.
def my_func(st):
res = []
#Iterate over the character
for index in range(len(st)):
if index % 2 == 0:
#Refer to each character via index and append modified character to list
res.append(st[index].upper())
else:
res.append(st[index].lower())
#Join the list into a string and return
return ''.join(res)
You can also iterate over the indexes and character simultaneously using enumerate
def my_func(st):
res = []
#Iterate over the characters
for index, c in enumerate(st):
if index % 2 == 0:
#Refer to each character via index and append modified character to list
res.append(c.upper())
else:
res.append(c.lower())
#Join the list into a string and return
return ''.join(res)
print(my_func('helloworld'))
The output will be
HeLlOwOrLd
You can store your operations beforehand and use them in join with enumerate:
def my_func(st):
operations = (str.lower, str.upper)
return ''.join(operations[i%2](x) for i, x in enumerate(st))
print(my_func('austin'))
# aUsTiN
Tweaking your code a bit, You can use the 'enumerate' and keep appending to the string based on the condition evaluations( for me this was easier since I have been coding in java :))
def myfunc(st):
str=''
for index, l in enumerate(st):
if index % 2 == 0:
str+=l.upper()
else:
str+=l.lower()
return str
def myfunc(str):
rstr = ''
for i in range(len(str) ):
if i % 2 == 0 :
# str[i].upper()
rstr = rstr + str[i].upper()
else:
#str[i].lower()
rstr = rstr + str[i].lower()
return rstr
l = 'YourString'
li=[]
for index,i in enumerate(l):
if index % 2 == 0:
i=i.lower()
li.append(i)
elif index % 2 == 1:
i=i.upper()
li.append(i)
print(''.join(li))
Use this enumerate method to perform your operation
return will terminate your function, so there isn't much point of the loop
st is the whole string, so st.upper() will yield the whole string in upper case.
You can use a bitwise and (&) to check for odd positions. The enumerate function will give you both the positions and the characters so you can easily use it in a list comprehension:
def upLow(s):
return "".join(c.lower() if i&1 else c.upper() for i,c in enumerate(s))
upLow("HelloWorld") # HeLlOwOrLd
The below code should do what you are looking for.
def myfunc(name):
str=""
lc=1;
for character in name:
if(lc%2==0):
str+=character.upper()
else:
str+=character.lower()
lc+=1
return str
def myfunc(a):
newString = ''
for count, ele in enumerate(a, 0):
if count %2 == 0:
newString += (a[count].lower())
else:
newString += ((a[count].upper()))
return newString
You can deconstruct string into collection of characters, apply transformations and reconstruct string back from them
Logic:
First enumerate() over the string to generate key-value pairs of characters and their positions
Then use comprehensions to loop over them and use conditional statement to return odd position characters in lower() case and even position in upper()
Now you have the list ready. Just join() it with an empty string '' to convert the list into a string
Code:
str = 'testing'
''.join([y.upper() if x%2 ==0 else y.lower() for x,y in enumerate(str)])
An isogram is a word that has no repeating letters, consecutive or non-consecutive. Implement a function that determines whether a string that contains only letters is an isogram. Assume the empty string is an isogram. Ignore letter case.
is_isogram("Dermatoglyphics" ) == true
is_isogram("aba" ) == false
is_isogram("moOse" ) == false # -- ignore letter case
Here is my code:
def is_isogram(string):
string = string.lower()
for char in string:
if string.count(char) > 1:
return False
else:
return True
And when I tried to run the test code Test.assert_equals(is_isogram("moOse"), False, "same chars may not be same case" ) It failed, but I thought I did convert everything into lowercase. Can someone help?
Try this:
def is_isogram(string):
string = string.lower()
for char in string:
if string.count(char) > 1:
return False
return True
In your code when is_isogram("moose") is called, it will see that the first character's ('m') count is not greater than 1. So it will return True. Once it hits the return statement, it will stop the execution for the rest string. So you should really write return True only after for-loop to make sure that the function checks for the whole string.
If however, at any point, it finds a character's count to be greater than 1, then it will simply return False and stop executing because there's no point of checking any more when one point is found where condition does not hold.
How about using sets? Casting the string into a set will drop the duplicate characters, causing isograms to return as True, as the length of the set won't differ from the length of the original string:
def is_isogram(s):
s = s.lower()
return len(set(s)) == len(s)
print is_isogram("Dermatoglyphics")
print is_isogram("aba")
print is_isogram("moOse")
print is_isogram("")
This outputs:
True
False
False
True
Try this :
def is_isogram(s):
string = s.lower()
if len(s) == len(set(string)):
return True
return False
Try this out:
def is_isogram(string):
return len(string) == len(set(string.lower()))
"Implement a function that determines whether a string that contains only letters is an isogram."
By using sets, you can create unique elements. So if there are any repeating numbers, it will only select one. By calling len() on these strings, you can compare the length to the original.
Sorry if I explained it poorly. I am working on this.
let us define an isogram well:
according to wikipedia An Isogram is a word in which no letter occurs more than once.
check here for more about an isogram
just remind letter
I write this code and it works for me :
def is_isogram(argument):
print(len(argument))
if isinstance(argument,str):
valeur=argument.lower()
if not argument:
return False
else:
for char in valeur:
if valeur.count(char)>1 or not char.isalpha():
return False
return True
else:
raise TypeError("need a string ")
NB: the hidden test is the fact that you must check if the char in the string is a alpha character a-z, when i add this it pass all the hiddens tests
up vote if this help
I reckon this might not be the best solution in terms of maximizing memory space and time. This answer is just for intuition purposes using a dictionary and two for loops:
def is_isogram(string):
#your code here
#create an empty dictionary
m={}
#loop through the string and check for repeating characters
for char in string:
#make all characters lower case to ignore case variations
char = char.lower()
if char in m:
m[char] += 1
else:
m[char] = 1
#loop through dictionary and get value counts.
for j, v in m.items():
#if there is a letter/character with a count > 1 return False
if v > 1:
return False
#Notice the scope of the "return True" command. It is outside.
return True
Please don't give me the answer just point me in the right direction, thank you. Also, I need to do this without isdigit().
I am trying to create a program that checks all the characters of a string and if any of them are not natural numbers then the program will return False otherwise it will return True.
This is what i have so far:
numbers = ["0123456789"]
if len(str) > 0:
for i in str:
if i not in numbers:
return False
else:
return True
I have a few test cases and the problem I'm having is that when I return, the whole program just ends. I need to find a way to include the else: return True
You would need to remove the numbers from the list as you are comparing each character to all the digits at once i.e "1" == "0123456789" , you also need to check every char before returning True:
def is_dig(s):
numbers = "0123456789" # single iterable of the numbers
for i in s:
if i not in numbers:
return False
return bool(s) # return outside the loop also catching empty string
A more efficient approach would be to use the ord and all:
def is_dig(s):
return len(s) > 0 and all(48 <= ord(ch) <= 57 for ch in s)
The ord of "0" is 48 and the ord of "9" is 57 so if the ord of the char falls in that range then you have a digit, if not all will short circuit and return False.
Using the ord without all and following your own logic would look something like:
def is_dig(s):
if not s: # empty string
return False
for ch in s:
if not 48 <= ord(ch) <= 57:
return False
return True
numbers = "0123456789"
if len(str) > 0:
for i in str:
if i not in numbers:
return False
return True
Thanks Padraic and everyone for the input. #Till Hoffmann your answer was exactly what i was looking for