I want to remove a character from a string in permutation....
Let us say that I have a function
def (string,char):
# remove char from string
Say I have aAabbAA as string and A as char then I want the strings [aabb,aAabb,aabbA,aabbA, aabbAA,aAabbA ,aAabbA ] as output that is A gets removed 3 times , 2 times , 1 times.
What is the best way in which I can do that ??
Thanks a lot....
Here is one crazy idea using recursion:
def f(s, c, start):
i = s.find(c, start)
if i < 0:
return [s]
else:
return f(s, c, i+1) + f(s[:i]+s[i+1:], c, i)
s = 'aAabbAA'
print f(s, 'A', 0)
# ['aAabbAA', 'aAabbA', 'aAabbA', 'aAabb', 'aabbAA', 'aabbA', 'aabbA', 'aabb']
Edit: Using set:
def f(s, c, start):
i = s.find(c, start)
if i < 0:
return set([s])
else:
return set.union(f(s, c, i+1), f(s[:i]+s[i+1:], c, i))
s = 'aAabbAA'
print f(s, 'A', 0)
# set(['aAabbA', 'aabbAA', 'aAabbAA', 'aabb', 'aAabb', 'aabbA'])
Edit 2: Using ternary operator:
def f(s, c, start):
i = s.find(c, start)
return [s] if i < 0 else f(s, c, i+1) + f(s[:i]+s[i+1:], c, i)
s = 'aAabbAA'
print f(s, 'A', 0)
# ['aAabbAA', 'aAabbA', 'aAabbA', 'aAabb', 'aabbAA', 'aabbA', 'aabbA', 'aabb']
Edit 3: timeit:
In [32]: timeit.timeit('x = f("aAabbAA", "A", 0)',
'from test3 import f', number=10000)
Out[32]: 0.11674594879150391
In [33]: timeit.timeit('x = deperm("aAabbAA", "A")',
'from test4 import deperm', number=10000)
Out[33]: 0.35839986801147461
In [34]: timeit.timeit('x = f("aAabbAA"*6, "A", 0)',
'from test3 import f', number=1)
Out[34]: 0.45998811721801758
In [35]: timeit.timeit('x = deperm("aAabbAA"*6, "A")',
'from test4 import deperm', number=1)
Out[35]: 7.8437530994415283
Here's a solution that might work. Basically I use a product of all possible combinations of the target character and an empty string.
from itertools import product
def deperm(st, c):
rsts = []
indexes = [i for i, s in enumerate(st) if s == c]
for i in product([c, ''], repeat=len(indexes)):
newst = ''
for j, ch in enumerate(st):
if j in indexes:
newst += i[indexes.index(j)]
else:
newst += ch
rsts.append(newst)
return rsts
for i in deperm('aAabbAA', 'A'):
print i
This outputs:
aAabbAA
aAabbA
aAabbA
aAabb
aabbAA
aabbA
aabbA
aabb
A recursive algorithm like so might help you here. Sorry I'm not a python champ, so you might have to tweak the syntax yourself. Psuedo code:
// returns a set of strings (permutations)
def permutation(string, char)
if len(string) == 0
return [] // return empty set
// get the set of permutations of suffix string recursively
set_of_perm_suffix = permutation(string[1:], char)
// prepend char to every string in set_of_perm
appended_set = prepend_char(set_of_perm_suffix , string[0])
// if the first char matches the one we should remove, we could either
// remove it or keep it.
if (string[0] == char)
return union_of_sets(set_of_perm_suffix , appended_set)
else
// the first char doesn't match the one we should remove,
// we need to keep it in every string of the set
return appended_set
Related
I am trying that age old question (there are multitudes of versions around) of finding the longest substring of a string which doesn't contain repeated characters. I can't work out why my attempt doesn't work properly:
def findLongest(inputStr):
resultSet = []
substr = []
for c in inputStr:
print ("c: ", c)
if substr == []:
substr.append([c])
continue
print(substr)
for str in substr:
print ("c: ",c," - str: ",str,"\n")
if c in str:
resultSet.append(str)
substr.remove(str)
else:
str.append(c)
substr.append([c])
print("Result set:")
print(resultSet)
return max(resultSet, key=len)
print (findLongest("pwwkewambb"))
When my output gets to the second 'w', it doesn't iterate over all the substr elements. I think I've done something silly, but I can't see what it is so some guidance would be appreciated! I feel like I'm going to kick myself at the answer...
The beginning of my output:
c: p
c: w
[['p']]
c: w - str: ['p']
c: w
[['p', 'w'], ['w']]
c: w - str: ['p', 'w'] # I expect the next line to say c: w - str: ['w']
c: k
[['w'], ['w']] # it is like the w was ignored as it is here
c: k - str: ['w']
c: k - str: ['w']
...
EDIT:
I replaced the for loop with
for idx, str in enumerate(substr):
print ("c: ",c," - str: ",str,"\n")
if c in str:
resultSet.append(str)
substr[idx] = []
else:
str.append(c)
and it produces the correct result. The only thing is that the empty element arrays get set with the next character. It seems a bit pointless; there must be a better way.
My expected output is kewamb.
e.g.
c: p
c: w
[['p']]
c: w - str: ['p']
c: w
[['p', 'w'], ['w']]
c: w - str: ['p', 'w']
c: w - str: ['w']
c: k
[[], [], ['w']]
c: k - str: []
c: k - str: []
c: k - str: ['w']
c: e
[['k'], ['k'], ['w', 'k'], ['k']]
c: e - str: ['k']
c: e - str: ['k']
c: e - str: ['w', 'k']
c: e - str: ['k']
...
Edit, per comment by #seymour on incorrect responses:
def find_longest(s):
_longest = set()
def longest(x):
if x in _longest:
_longest.clear()
return False
_longest.add(x)
return True
return ''.join(max((list(g) for _, g in groupby(s, key=longest)), key=len))
And test:
In [101]: assert find_longest('pwwkewambb') == 'kewamb'
In [102]: assert find_longest('abcabcbb') == 'abc'
In [103]: assert find_longest('abczxyabczxya') == 'abczxy'
Old answer:
from itertools import groupby
s = set() ## for mutable access
''.join(max((list(g) for _, g in groupby('pwwkewambb', key=lambda x: not ((s and x == s.pop()) or s.add(x)))), key=len))
'kewamb'
groupby returns an iterator grouped based on the function provided in the key argument, which by default is lambda x: x. Instead of the default we are utilizing some state by using a mutable structure (which could have been done a more intuitive way if using a normal function)
lambda x: not ((s and x == s.pop()) or s.add(x))
What is happening here is since I can't reassign a global assignment in a lambda (again I can do this, using a proper function), I just created a global mutable structure that I can add/remove. The key (no pun) is that I only keep elements that I need by using a short circuit to add/remove items as needed.
max and len are fairly self explanatory, to get the longest list produced by groupby
Another version without the mutable global structure business:
def longest(x):
if hasattr(longest, 'last'):
result = not (longest.last == x)
longest.last = x
return result
longest.last = x
return True
''.join(max((list(g) for _, g in groupby('pwwkewambb', key=longest)), key=len))
'kewamb'
Not sure what is wrong in your attempt, but it's complex and in:
for str in substr:
print ("c: ",c," - str: ",str,"\n")
if c in str:
resultSet.append(str)
substr.remove(str)
you're removing elements from a list while iterating on it: don't do that, it gives unexpected results.
Anyway, my solution, not sure it's intuitive, but it's probably simpler & shorter:
slice the string with an increasing index
for each slice, create a set and store letters until you reach the end of the string or a letter is already in the set. Your index is the max length
compute the max of this length for every iteration & store the corresponding string
Code:
def findLongest(s):
maxlen = 0
longest = ""
for i in range(0,len(s)):
subs = s[i:]
chars = set()
for j,c in enumerate(subs):
if c in chars:
break
else:
chars.add(c)
else:
# add 1 when end of string is reached (no break)
# handles the case where the longest string is at the end
j+=1
if j>maxlen:
maxlen=j
longest=s[i:i+j]
return longest
print(findLongest("pwwkewambb"))
result:
kewamb
Depends on your definition of repeated characters: if you mean consecutive, then the approved solution is slick, but not of characters appearing more than once (e.g.: pwwkewabmb -> 'kewabmb' ).
Here's what I came up with (Python 2):
def longest(word):
begin = 0
end = 0
longest = (0,0)
for i in xrange(len(word)):
try:
j = word.index(word[i],begin,end)
# longest?
if end-begin >= longest[1]-longest[0]:
longest = (begin,end)
begin = j+1
if begin==end:
end += 1
except:
end = i+1
end=i+1
if end-begin >= longest[1]-longest[0]:
longest = (begin,end)
return word[slice(*longest)]
Thus
>>> print longest('pwwkewabmb')
kewabm
>>> print longest('pwwkewambb')
kewamb
>>> print longest('bbbb')
b
My 2-cents:
from collections import Counter
def longest_unique_substr(s: str) -> str:
# get all substr-ings from s, starting with the longest one
for substr_len in range(len(s), 0, -1):
for substr_start_index in range(0, len(s) - substr_len + 1):
substr = s[substr_start_index : substr_start_index + substr_len]
# check if all substr characters are unique
c = Counter(substr)
if all(v == 1 for v in c.values()):
return substr
# ensure empty string input returns ""
return ""
Run:
In : longest_unique_substr('pwwkewambb')
Out: 'kewamb'
s=input()
ma=0
n=len(s)
l=[]
a=[]
d={}
st=0;i=0
while i<n:
if s[i] not in d:
d[s[i]]=i
l.append(s[i])
else:
t=d[s[i]]
d[s[i]]=i
s=s[t+1:]
d={}
n=len(s)
if len(l)>=3:
a.append(l)
ma=max(ma,len(l))
l=[];i=-1
i=i+1
if len(l)!=0 and len(l)>=3:
a.append(l)
ma=max(ma,len(l))
if len(a)==0:
print("-1")
else:
for i in a:
if len(i)==ma:
for j in i:
print(j,end="")
break
how can i write a python program to intake some alphabets in and print out (alphabets+n) in the output. Example
my_string = 'abc'
expected_output = 'cde' # n=2
One way I've thought is by using str.maketrans, and mapping the original input to (alphabets + n). Is there any other way?
PS: xyz should translate to abc
I've tried to write my own code as well for this, (apart from the infinitely better answers mentioned):
number = 2
prim = """abc! fgdf """
final = prim.lower()
for x in final:
if(x =="y"):
print("a", end="")
elif(x=="z"):
print("b", end="")
else:
conv = ord(x)
x = conv+number
print(chr(x),end="")
Any comments on how to not convert special chars? thanks
If you don't care about wrapping around, you can just do:
def shiftString(string, number):
return "".join(map(lambda x: chr(ord(x)+number),string))
If you do want to wrap around (think Caesar chiffre), you'll need to specify a start and an end of where the alphabet begins and ends:
def shiftString(string, number, start=97, num_of_symbols=26):
return "".join(map(lambda x: chr(((ord(x)+number-start) %
num_of_symbols)+start) if start <= ord(x) <= start+num_of_symbols
else x,string))
That would, e.g., convert abcxyz, when given a shift of 2, into cdezab.
If you actually want to use it for "encryption", make sure to exclude non-alphabetic characters (like spaces etc.) from it.
edit: Shameless plug of my Vignère tool in Python
edit2: Now only converts in its range.
How about something like
>>> my_string = "abc"
>>> n = 2
>>> "".join([ chr(ord(i) + n) for i in my_string])
'cde'
Note As mentioned in comments the question is bit vague about what to do when the edge cases are encoundered like xyz
Edit To take care of edge cases, you can write something like
>>> from string import ascii_lowercase
>>> lower = ascii_lowercase
>>> input = "xyz"
>>> "".join([ lower[(lower.index(i)+2)%26] for i in input ])
'zab'
>>> input = "abc"
>>> "".join([ lower[(lower.index(i)+2)%26] for i in input ])
'cde'
I've made the following change to the code:
number = 2
prim = """Special() ops() chars!!"""
final = prim.lower()
for x in final:
if(x =="y"):
print("a", end="")
elif(x=="z"):
print("b", end="")
elif (ord(x) in range(97, 124)):
conv = ord(x)
x = conv+number
print(chr(x),end="")
else:
print(x, end="")
**Output**: urgekcn() qru() ejctu!!
test_data = (('abz', 2), ('abc', 3), ('aek', 26), ('abcd', 25))
# translate every character
def shiftstr(s, k):
if not (isinstance(s, str) and isinstance(k, int) and k >=0):
return s
a = ord('a')
return ''.join([chr(a+((ord(c)-a+k)%26)) for c in s])
for s, k in test_data:
print(shiftstr(s, k))
print('----')
# translate at most 26 characters, rest look up dictionary at O(1)
def shiftstr(s, k):
if not (isinstance(s, str) and isinstance(k, int) and k >=0):
return s
a = ord('a')
d = {}
l = []
for c in s:
v = d.get(c)
if v is None:
v = chr(a+((ord(c)-a+k)%26))
d[c] = v
l.append(v)
return ''.join(l)
for s, k in test_data:
print(shiftstr(s, k))
Testing shiftstr_test.py (above code):
$ python3 shiftstr_test.py
cdb
def
aek
zabc
----
cdb
def
aek
zabc
It covers wrapping.
is there a better way to find the first appearance of one of the chars: 'x','y','z' in someStr?
def findFirstAppearance(someStr):
x = someStr.find('x');
y = someStr.find('y');
z = someStr.find('z');
if x == -1: x= len(someStr);
if y == -1: y= len(someStr);
if z == -1: z= len(someStr);
return min(x,y,z);
for example: for someStr = "axby" it should return 1.
for someStr = "aybx" it should also return 1.
thanks!
Maybe:
>>> s = 'this string x contains y several letters z'
>>> next(i for i,c in enumerate(s) if c in 'xyz')
12
>>> s[12]
'x'
This will raise an exception if it's not found, which could be fixed by using a default value:
>>> next(i for i,c in enumerate(s) if c in 'Q')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> next((i for i,c in enumerate(s) if c in 'Q'), -1)
-1
You could also pre-construct a set to test membership in:
>>> special = set("vmp")
>>> next((i for i,c in enumerate(s) if c in special), -1)
27
which might be faster if there were a lot of letters to test against; it'll depend a lot on the sizes involved. Easy to experiment if it matters, but (spoiler alert) it probably doesn't.
Here's an alternative using regular expressions.
import re
def find_first_dx(needles, haystack):
match = re.search('|'.join(map(re.escape, needles)), haystack)
return match.start() if match else -1
Examples:
>>> find_first_dx('xyz', 'abcyax')
3
>>> find_first_dx('xyz.', 'a.bcyax')
1
>>> find_first_dx('xyz', 'fee fi foe fum')
-1
>>> find_first_dx(['foe', 'fum'], 'fee fi foe fum')
7
I think this is what you're looking for. This finds the first occurance of one of may chars (items) in a string. It works just like str.find.
def findany(string, items, start, end=-1):
if end == -1:
end = len(string)
for i in range(start, end):
c = string[i]
if c in items:
return i
return -1
# 01234567
inp = "hellozxy"
print findany(inp, "xyz") # 5 = z
print findany(inp, "?") # -1 = not found
print findany(inp, ["o", "l"], 3) # 3, skips the first 'l'
Note: You pass a list of chars (1-character strings) as items. In python, a string is just that. If you pass something like ["x", "y", "blah"], it won't work (it'll ignore "blah").
This should work:
def findany(s1, s2):
for i, x in enumerate(s1):
if x in s2:
return i
return -1
Use enumerate(), it yields a tuple for each character of the string.
Tuple's first element is the index and second element is the character itself.
In [103]: def find_first(strs):
.....: for i,x in enumerate(strs):
.....: if x in 'xyz': #if current character is either
#'x' or 'y' or 'z' then return index
.....: return i
.....: return -1 #if the loop completed successfully then return -1
.....:
In [104]: find_first("fooxbaryzx")
Out[104]: 3
In [105]: find_first("qwerty")
Out[105]: 5
In [106]: find_first("qwert")
Out[106]: -1
In [107]: find_first("axby")
Out[107]: 1
In [108]: find_first("aybx")
Out[108]: 1
For a lot of chars, you should seriously think about using a regular expression,
especially if you are doing this in a loop in your application:
import re
def findall(string, chars)
m = re.search("[%s]" % chars, string, re.DOTALL)
if m:
return m.start()
return -1
this should be at least 100x faster than a pure-python loop with a call to "find"
for each char.
Just be aware that if you need to find a char that is used for other
purposes inside regexps "[ ]" , you should escape them (like "-", "^")
I have a String like 'LETTER' now i have another string "LTR" when the string is checked with the previous one the remaining letters are "ETE" how can i extract this from the main string in python. The order of the letters doesn't matter any way we should get the remaining letters
use ndiff() from difflib library:
>>> from difflib import *
>>> list(ndiff("LETTER","LTR"))
[' L', '- E', ' T', '- T', '- E', ' R']
#so filter out letters which doesn't have '-'
>>> ''.join(x.strip('-').strip() for x in filter(lambda x:'-' in x,ndiff("LETTER","LTR")))
'ETE'
>>> ''.join(x.strip('-').strip() for x in filter(lambda x:'-' in x,ndiff("stack","tc")))
'sak'
you can use Counter(), incase if the order of letters doesn't matter:
>>> from collections import Counter
>>> str1="LETTER"
>>> str2="LTR"
>>> c=Counter(str1)-Counter(str2)
>>> c
Counter({'E': 2, 'T': 1})
>>> ''.join(x*c[x] for x in c)
'EET
Popular question:-) I think this is a very readable one:
s=list("LETTER")
p=list("LTR")
while p: s.remove(p.pop())
Now
print("".join(s))
prints "ETE"
#!/bin/env python
def str_diff(s, rem):
for x in rem:
pos = s.find(x)
if pos >= 0: s = s[:pos] + s[pos+1:]
return s
print str_diff("LETTER", "LTR") # ETE
print str_diff("LETTER", "LTTR") # EE
print str_diff("LETTER", "LTRxyz") # ETE
This seems to do what you want to do. It preserves original ordering, works for multiples of the same letter in the "removal set", and doesn't barf if the "removal set" includes a character not in the original string.
>>> x = "LETTER"
>>> r = "LTR"
>>> y = x
>>> for c in r:
... y = y.replace(c, '', 1)
...
>>> y
'ETE'
>>> x = "LETTER"
>>> for c in "LTR":
... if c in x:
... p = x.find(c)
... if p < len(x)-1:
... x = x[:p]+x[p+1:]
... else:
... x = x[:p]
...
>>> x
'ETE'
Here is a fairly straightforward and readable solution that correctly preserves the ordering and duplicates of the input string:
def omit(s, discard):
discard = list(discard)
for c in s:
if c not in discard:
yield c
else:
discard.remove(c)
>>> ''.join(omit('LETTER', 'LTR'))
'ETE'
def remaining(my_string, my_string_2):
output = ""
i = 0
j = 0
while i < len(my_string) and j < len(my_string_2):
if my_string[i] != my_string_2[j]:
output += my_string[i]
else:
j += 1
i+=1
if i < len(my_string):
output+=my_string[i:len(my_string)]
return output
result = remaining("LETTER", "LTR")
print result
Returns 'ETE'
l1='LETTER'
l2='LTR'
occur=[]
for i in range(0,len(l1)):
if l1[i] in occur:
print l1[i]
if l1[i] in l2:
occur.append(l1[i])
else:
print l1[i]
Suppose we have a string a = "01000111000011" with n=5 "1"s. The ith "1", I would like to replace with the ith character in "ORANGE".
My result should look like:
b = "0O000RAN0000GE"
What could be the finest way to solve this problem in Python? Is it possible to bind an index to each substitution?
Many thanks!
Helga
Tons of answers/ways to do it. Mine uses a fundamental assumption that your #of 1s is equal to the length of the word you are subsituting.
a = "01000111000011"
a = a.replace("1", "%s")
b = "ORANGE"
print a % tuple(b)
Or the pythonic 1 liner ;)
print "01000111000011".replace("1", "%s") % tuple("ORANGE")
a = '01000111000011'
for char in 'ORANGE':
a = a.replace('1', char, 1)
Or:
b = iter('ORANGE')
a = ''.join(next(b) if i == '1' else i for i in '01000111000011')
Or:
import re
a = re.sub('1', lambda x, b=iter('ORANGE'): b.next(), '01000111000011')
s_iter = iter("ORANGE")
"".join(next(s_iter) if c == "1" else c for c in "01000111000011")
If the number of 1's in your source string doesn't match the length of your replacement string you can use this solution:
def helper(source, replacement):
i = 0
for c in source:
if c == '1' and i < len(replacement):
yield replacement[i]
i += 1
else:
yield c
a = '010001110001101010101'
b = 'ORANGE'
a = ''.join(helper(a, b)) # => '0O000RAN000GE01010101'
Improving on bluepnume's solution:
>>> from itertools import chain, repeat
>>> b = chain('ORANGE', repeat(None))
>>> a = ''.join((next(b) or c) if c == '1' else c for c in '010001110000110101')
>>> a
'0O000RAN0000GE0101'
[EDIT]
Or even simpler:
>>> from itertools import chain, repeat
>>> b = chain('ORANGE', repeat('1'))
>>> a = ''.join(next(b) if c == '1' else c for c in '010001110000110101')
>>> a
'0O000RAN0000GE0101'
[EDIT] #2
Also this works:
import re
>>> r = 'ORANGE'
>>> s = '010001110000110101'
>>> re.sub('1', lambda _,c=iter(r):next(c), s, len(r))
'0O000RAN0000GE0101'