Here is my code:
def del_rep_vow(s):
'''
>>> del_rep_vow('adaptation')
'adpttion'
>>> del_rep_vow('repetitions')
'reptitons'
>>> del_rep_vow('kingkong')
'kingkong'
>>> del_rep_vow('aeiouaeiou')
'aeiou'
'''
final_list = []
for i in s:
if i not in final_list:
final_list.append(i)
return ''.join(final_list)
if __name__ == "__main__":
import doctest
doctest.testmod(verbose=True)
I don't know how to make the restriction that only repeated vowels have to be deleted once they are in the list. Any help will be very welcome.
Output of 'adaptation' must be 'adpttion', for example.
You should maintain a Python set of vowel characters already seen. For each new encountered letter as you walk down the string, only append a vowel if it is not in the set.
def del_rep_vow(s):
vowels_seen = set()
final_list = []
for i in s:
if i in ['a', 'e', 'i', 'o', 'u']:
if i not in vowels_seen:
final_list.append(i)
vowels_seen.add(i)
else:
final_list.append(i)
return ''.join(final_list)
print(del_rep_vow('adaptation')) # 'adpttion'
print(del_rep_vow('repetitions')) # 'reptitons'
print(del_rep_vow('kingkong')) # 'kingkong'
print(del_rep_vow('aeiouaeiou')) # 'aeiou'
I feel this is pretty concise:
def del_rep_vow(s):
for ch in 'eaiou':
if ch in s:
i = s.index(ch) + 1
s = s[:i] + s[i:].replace(ch, '')
return s
print(del_rep_vow('adaptation'))
print(del_rep_vow('repetitions'))
print(del_rep_vow('kingkong'))
print(del_rep_vow('aeiouaeiou'))
Result:
adpttion
reptitons
kingkong
aeiou
You could also keep your initial code, adding just a little condition to the test:
def del_rep_vow(s):
final_list = []
vowels = 'aeiou'
for i in s:
if i not in vowels or i not in final_list: # allowed consonants to be added every time
final_list.append(i)
return ''.join(final_list)
The str.partition method closely matches your need. It splits the string at the first occurrence of a separator and returns a 3-tuple containing the part before the separator, the separator itself or "" if not found, and the part after the separator. All that remains is to remove the vowel from the after-part.
def del_rep_vow(s):
for v in 'aeiou':
before, vowel, after = s.partition(v)
s = before + vowel + after.replace(v, '')
return s
print(del_rep_vow('adaptation')) # 'adpttion'
print(del_rep_vow('repetitions')) # 'reptitons'
print(del_rep_vow('kingkong')) # 'kingkong'
print(del_rep_vow('aeiouaeiou')) # 'aeiou'
You can maintain 2 lists of letters: one for the vowels you have seen so far, and other for the remaining letters in the string.
vowels = []
remaining = []
for c in s:
if c in 'aeiou':
if c in vowels:
continue
vowels.append(c)
remaining.append(c)
Here's another approach
def del_repts(x):
vowels = 'aeiou'
foundVowels = ''
rslt = ''
for c in x:
if c in vowels:
if c not in foundVowels:
rslt += c
foundVowels += c
else:
rslt += c
return rslt
inl = ['adaptation', 'repetitions', 'kingkong', 'aeiouaeiou']
for itm in inl:
print(f'{itm}\t->\t{del_repts(itm)}' )
Yields:
adaptation -> adpttion
repetitions -> reptitons
kingkong -> kingkong
aeiouaeiou -> aeiou
recursive solution:
def del_rep_vow(s):
return del_rep_vow(s[:-1]) + ('' if s[-1] in 'aeiou' and s[-1] in s[:-1] else s[-1]) if s else ''
del_rep_vow('repetitions') # reptitons'
Related
Given a string, I want to reverse only the vowels and leave the remaining string as it is. If input is fisherman output should be fashermin. I tried the following code:
a=input()
l=[]
for i in a:
if i in 'aeiou':
l.append(i)
siz=len(l)-1
for j in range(siz,-1,-1):
for k in a:
if k in 'aeiou':
a.replace(k,'l')
print(a)
What changes should be made in this code to get the desired output?
It is a little easier to turn your word into a list of letters and back:
a=input('Enter word: ')
l=[]
for i in a:
if i in 'aeiou':
l.append(i)
letters = list(a)
for i in range(len(letters)):
if letters[i] in 'aeiou':
letters[i] = l.pop(-1)
print(''.join(letters))
You have few logical mistakes in the code.
You need to save the o/p of .replace function in another string
a= a.replace(k,'l')
'l' is a string. I am sure it was list access that you were going for, so the correct syntax is: a= a.replace(k,l[j])
When replacing if you use the same string(string 'a' in your case), it will lead to all vowels getting replaced by a same vowel.
Using the same variable names, you used, following is one of the correct ways to do it:
a=input()
l=""
for i in a:
if i in 'aeiouAEIOU':
l+=i
new_a = ""
for k in a:
if k in "aeiouAEIOU":
new_a += l[-1]
l = l[:-1]
else:
new_a += k
print(a)
print(new_a)
Here is a piece of code that I have worked on that is the same question.
Write a program to reverse only the vowels in the string.
Example:
Input:
India
Output:
andiI
def revv(word):
a = ''
b = ''
for x in word:
if x in 'aeiouAEIOU':
a = a+x
b = b+'-'
else:
b = b+x
c = ''
d = 0
a = a[::-1]
for x in b:
if x=='-':
c = c+a[d]
d = d+1
else:
c = c+x
print(c)
revv('India')
Output:
andiI
This must work. First found vowels and and indexes of the vowels also you need to store it in a variable. After that you can reverse it easly buy going backword.
a = "fisherman"
def isVowel(c):
if c == "a" or c == "e" or c == "u" or c == "i" or c == "o":
return True
return False
def reverseOnlyVowels(string):
indexes = []
chars = []
# get vowels and indexes
for index, i in enumerate(list(string)):
if isVowel(i):
indexes.append(index)
chars.append(i)
# reverse vowels
stringList = list(string)
index1 = 0
for i, index in zip(chars[::-1], indexes[::-1]):
stringList[index] = chars[index1]
index1 += 1
return "".join(stringList)
print(reverseOnlyVowels(a))
def r(s):
str = []
for i in len(s):
if (s[i]=='_'):
str = s[i] + str
continue
str = s[i] + str
return str
I tried using the above code to convert the following string
Input: ab_cde
Expected Output: ed_cba
s = 'ab_cde'
out = ''
for a, b in zip(s, s[::-1]):
if b != '_' and a != '_':
out += b
else:
out += a
print(out)
Prints:
ed_cba
EDIT: For more fixed points:
s = 'ab_cde_f_ghijk_l'
i, out = iter(ch for ch in s[::-1] if ch != '_'), ''
out = ''.join(ch if ch == '_' else next(i) for ch in s)
print(out)
Prints:
lk_jih_g_fedcb_a
The main idea is to check all the positions of the underscore _, save them and reverse the string without them, to insert them again after reversing.
import re
def r(s):
# check where all the underscore are
underscore_positions = [m.start() for m in re.finditer('_', s)]
# get list of reversed chars without underscores
reversed_chars = [c for c in reversed(s) if c != '_']
# put underscore back where they where
for p in underscore_positions:
reversed_chars.insert(p, '_')
# profit
return "".join(reversed_chars)
The function can be modified to have a different fixed character.
I also uses the package re for the regex function to identify the _, you can do with a simple loop as underscore_positions = [i for i, c in enumerate(s) if c =='_'] if you prefer.
def fixed_reverse(s, ch):
idxs = [-1] + [i for i, x in enumerate(s) if x == ch] + [len(s)]
idxs = [x - i + 1 for i, x in enumerate(idxs)]
chars = "".join(x for x in s if x != ch)[::-1]
return ch.join(chars[a:b] for a, b in zip(idxs[:-1], idxs[1:]))
>>> fixed_reverse("ab_cde_f_ghijk_l", "_")
'lk_jih_g_fedcb_a'
This works by:
Storing the locations of the fixed-point character "_".
Reversing the string with the "_" characters removed.
Inserting the "_" back into the correct locations.
I am doing googles python class. And came across this problem:
# A. match_ends
# Given a list of strings, return the count of the number of
# strings where the string length is 2 or more and the first
# and last chars of the string are the same.
# Note: python does not have a ++ operator, but += works.
I tried different approaches, but cant seem to get it to work. This is what i got now:
def match_ends(words):
words=sorted(words, key=len)
for i in words:
if len(i)<2:
print(i)
words=words[1:]
print(words)
for i in words:
if i[0:2]==i[-2:]:
x=[]
x.append[i]
How is this done?
Easy to accomplish using sum and a generator expression:
def match_ends(words):
return sum(len(word) >= 2 and word[0] == word[-1] for word in words)
You could simply do this:
def match_ends(words):
count = 0
for word in words:
if len(word) >= 2 and word[0] == word[-1]:
count += 1
return count
A more pythonic solution might be
def func(s):
return len(s) >= 2 and s[0] == s[-1]
str_list = ['applea', 'b', 'cardc']
filtered_list = [s for s in str_list if (len(s) >= 2 and s[0] == s[-1])]
# or
filtered_list = list(filter(func, str_list))
count = len(filtered_list)
pretty much the same as previous answers, but lambda
match_ends = lambda ws: sum(1 for w in ws if len(w)>1 and w[0] == w[-1])
or 'expanded' form
match_ends = lambda words: sum(1 for word in words if len(word)>1 and word[0] == word[-1])
I want to create a new string from a given string with alternate uppercase and lowercase.
I have tried iterating over the string and changing first to uppercase into a new string and then to lower case into another new string again.
def myfunc(x):
even = x.upper()
lst = list(even)
for itemno in lst:
if (itemno % 2) !=0:
even1=lst[1::2].lowercase()
itemno=itemno+1
even2=str(even1)
print(even2)
Since I cant change the given string I need a good way of creating a new string alternate caps.
Here's a onliner
"".join([x.upper() if i%2 else x.lower() for i,x in enumerate(mystring)])
You can simply randomly choose for each letter in the old string if you should lowercase or uppercase it, like this:
import random
def myfunc2(old):
new = ''
for c in old:
lower = random.randint(0, 1)
if lower:
new += c.lower()
else:
new += c.upper()
return new
Here's one that returns a new string using with alternate caps:
def myfunc(x):
seq = []
for i, v in enumerate(x):
seq.append(v.upper() if i % 2 == 0 else v.lower())
return ''.join(seq)
This does the job also
def foo(input_message):
c = 0
output_message = ""
for m in input_message:
if (c%2==0):
output_message = output_message + m.lower()
else:
output_message = output_message + m.upper()
c = c + 1
return output_message
Here's a solution using itertools which utilizes string slicing:
from itertools import chain, zip_longest
x = 'inputstring'
zipper = zip_longest(x[::2].lower(), x[1::2].upper(), fillvalue='')
res = ''.join(chain.from_iterable(zipper))
# 'iNpUtStRiNg'
Using a string slicing:
from itertools import zip_longest
s = 'example'
new_s = ''.join(x.upper() + y.lower()
for x, y in zip_longest(s[::2], s[1::2], fillvalue=''))
# ExAmPlE
Using an iterator:
s_iter = iter(s)
new_s = ''.join(x.upper() + y.lower()
for x, y in zip_longest(s_iter, s_iter, fillvalue=''))
# ExAmPlE
Using the function reduce():
def func(x, y):
if x[-1].islower():
return x + y.upper()
else:
return x + y.lower()
new_s = reduce(func, s) # eXaMpLe
This code also returns alternative caps string:-
def alternative_strings(strings):
for i,x in enumerate(strings):
if i % 2 == 0:
print(x.upper(), end="")
else:
print(x.lower(), end= "")
return ''
print(alternative_strings("Testing String"))
def myfunc(string):
# Un-hash print statements to watch python build out the string.
# Script is an elementary example of using an enumerate function.
# An enumerate function tracks an index integer and its associated value as it moves along the string.
# In this example we use arithmetic to determine odd and even index counts, then modify the associated variable.
# After modifying the upper/lower case of the character, it starts adding the string back together.
# The end of the function then returns back with the new modified string.
#print(string)
retval = ''
for space, letter in enumerate(string):
if space %2==0:
retval = retval + letter.upper()
#print(retval)
else:
retval = retval + letter.lower()
#print(retval)
print(retval)
return retval
myfunc('Thisisanamazingscript')
I have the follwing string and I split it:
>>> st = '%2g%k%3p'
>>> l = filter(None, st.split('%'))
>>> print l
['2g', 'k', '3p']
Now I want to print the g letter two times, the k letter one time and the p letter three times:
ggkppp
How is it possible?
You could use generator with isdigit() to check wheter your first symbol is digit or not and then return following string with appropriate count. Then you could use join to get your output:
''.join(i[1:]*int(i[0]) if i[0].isdigit() else i for i in l)
Demonstration:
In [70]: [i[1:]*int(i[0]) if i[0].isdigit() else i for i in l ]
Out[70]: ['gg', 'k', 'ppp']
In [71]: ''.join(i[1:]*int(i[0]) if i[0].isdigit() else i for i in l)
Out[71]: 'ggkppp'
EDIT
Using re module when first number is with several digits:
''.join(re.search('(\d+)(\w+)', i).group(2)*int(re.search('(\d+)(\w+)', i).group(1)) if re.search('(\d+)(\w+)', i) else i for i in l)
Example:
In [144]: l = ['12g', '2kd', 'h', '3p']
In [145]: ''.join(re.search('(\d+)(\w+)', i).group(2)*int(re.search('(\d+)(\w+)', i).group(1)) if re.search('(\d+)(\w+)', i) else i for i in l)
Out[145]: 'ggggggggggggkdkdhppp'
EDIT2
For your input like:
st = '%2g_%3k%3p'
You could replace _ with empty string and then add _ to the end if the work from list endswith the _ symbol:
st = '%2g_%3k%3p'
l = list(filter(None, st.split('%')))
''.join((re.search('(\d+)(\w+)', i).group(2)*int(re.search('(\d+)(\w+)', i).group(1))).replace("_", "") + '_' * i.endswith('_') if re.search('(\d+)(\w+)', i) else i for i in l)
Output:
'gg_kkkppp'
EDIT3
Solution without re module but with usual loops working for 2 digits. You could define functions:
def add_str(ind, st):
if not st.endswith('_'):
return st[ind:] * int(st[:ind])
else:
return st[ind:-1] * int(st[:ind]) + '_'
def collect(l):
final_str = ''
for i in l:
if i[0].isdigit():
if i[1].isdigit():
final_str += add_str(2, i)
else:
final_str += add_str(1, i)
else:
final_str += i
return final_str
And then use them as:
l = ['12g_', '3k', '3p']
print(collect(l))
gggggggggggg_kkkppp
One-liner Regex way:
>>> import re
>>> st = '%2g%k%3p'
>>> re.sub(r'%|(\d*)(\w+)', lambda m: int(m.group(1))*m.group(2) if m.group(1) else m.group(2), st)
'ggkppp'
%|(\d*)(\w+) regex matches all % and captures zero or moredigit present before any word character into one group and the following word characters into another group. On replacement all the matched chars should be replaced with the value given in the replacement part. So this should loose % character.
or
>>> re.sub(r'%(\d*)(\w+)', lambda m: int(m.group(1))*m.group(2) if m.group(1) else m.group(2), st)
'ggkppp'
Assumes you are always printing single letter, but preceding number may be longer than single digit in base 10.
seq = ['2g', 'k', '3p']
result = ''.join(int(s[:-1] or 1) * s[-1] for s in seq)
assert result == "ggkppp"
LATE FOR THE SHOW BUT READY TO GO
Another way, is to define your function which converts nC into CCCC...C (ntimes), then pass it to a map to apply it on every element of the list l coming from the split over %, the finally join them all, as follows:
>>> def f(s):
x = 0
if s:
if len(s) == 1:
out = s
else:
for i in s:
if i.isdigit():
x = x*10 + int(i)
out = x*s[-1]
else:
out = ''
return out
>>> st
'%4g%10k%p'
>>> ''.join(map(f, st.split('%')))
'ggggkkkkkkkkkkp'
>>> st = '%2g%k%3p'
>>> ''.join(map(f, st.split('%')))
'ggkppp'
Or if you want to put all of these into one single function definition:
>>> def f(s):
out = ''
if s:
l = filter(None, s.split('%'))
for item in l:
x = 0
if len(item) == 1:
repl = item
else:
for c in item:
if c.isdigit():
x = x*10 + int(c)
repl = x*item[-1]
out += repl
return out
>>> st
'%2g%k%3p'
>>> f(st)
'ggkppp'
>>>
>>> st = '%4g%10k%p'
>>>
>>> f(st)
'ggggkkkkkkkkkkp'
>>> st = '%4g%101k%2p'
>>> f(st)
'ggggkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkpp'
>>> len(f(st))
107
EDIT :
In case of the presence of _ where the OP does not want this character to be repeated, then the best way in my opinion is to go with re.sub, it will make things easier, this way:
>>> def f(s):
pat = re.compile(r'%(\d*)([a-zA-Z]+)')
out = pat.sub(lambda m:int(m.group(1))*m.group(2) if m.group(1) else m.group(2), s)
return out
>>> st = '%4g_%12k%p__%m'
>>> f(st)
'gggg_kkkkkkkkkkkkp__m'
Loop the list, check first entry for number, and then append the second digit onwards:
string=''
l = ['2g', 'k', '3p']
for entry in l:
if len(entry) ==1:
string += (entry)
else:
number = int(entry[0])
for i in range(number):
string += (entry[1:])