I'm trying to link two string together recursively, but not getting the expected results:
For the two strings "abcd" and "xyz" - expected output should be "axbyczd":
def strr(str1, str2):
def recstr(str1, str2, prn):
if str1 == '':
return str2
if str2 == '':
return str1
else:
return prn + recstr(str1[:len(str1)-len(prn)],str2[:len(str2)-len(prn)],prn)
return recstr(str1, str2, '')
print strr("abcdef","12345")
When you ran out of characters in either string, you returned the other string without concatenating it to a running accumulator. Look at what I do when s1 or s2 is empty.
Also, in your recursive case, you have a very complex slicing of s1 and s2. You should really only need to slice s1[1:] and s2[1:]
This should do it
def recstr(s1, s2, answer=''):
if not s1:
return answer+s2
if not s2:
return answer+s1
return recstr(s1[1:], s2[1:], answer+s1[0]+s2[0])
In [15]: s1,s2 = 'abcd', 'xyz'
In [16]: print recstr(s1,s2)
axbyczd
Of course, a much cleaner way to do this would be to use itertools.izip_longest and itertools.chain.from_iterable:
In [23]: zips = itertools.izip_longest(s1,s2, fillvalue='')
In [24]: ''.join(itertools.chain.from_iterable(zips))
Out[24]: 'axbyczd'
[Thanks #AshwiniChaudhary for pointing out the fillvalue param in izip_longest]
Hope this helps
Related
Word Problem:
Create a function to interleave the letters of two strings (starting with the first string from right to left) and return the resultant string.
def interleave(s1: str, s2: str) -> str:
I was able to solve this word problem but I need help putting it in a function
def interleave(s1: str, s2: str) -> str:
string1 = s1[::-1]
string2 = s2[::-1]
for i in range(len(string1)):
print(string2[i] + string1[i], end = "")
return print
print(interleave("1234", "5678"))
I can't tell from your question what should happen when the strings are unequal in length. My basic solution would be
def interleave(str1, str2):
return ''.join(c1 + c2 for c1, c2 in zip(str1, str2))
but this will stop with the shortest of the two input strings.
Right now, the function prints the results. Instead store the results in a variable, which you return when done.
Like so:
#!/usr/bin/python3
def interleave(s1: str, s2: str) -> str:
string1 = s1[::-1]
string2 = s2[::-1]
interleaved_string = ''
for i in range(len(string1)):
interleaved_string += string2[i] + string1[i]
return interleaved_string
print(interleave("1234", "5678"))
Your whole loop can be made into a one-liner using zip and map (or a generator comprehension):
def interleave(str1: str, str2: str) -> str:
assert len(str1) == len(str2), "Strings must be equal in length." # Alternatively, consider itertools.zip_longest
return ''.join(map(''.join, zip(str1[::-1], str2[::-1])))
Input:
joined_str = interleave("1234", "5678")
print(joined_str)
Output:
'48372615'
I have following regexes / code snippet:
import js_regex
# I got 2 regexes
a = js_regex.compile(r"^[A-Z]{2}[A-Z0-9]{9}[0-9]$")
b = js_regex.compile(r"^\$[A-Z]{3}$")
# which I can test like this:
if a.match("BE46138E7195"):
print("match a")
if b.match("$USD"):
print("match b")
if not a.match("BDDD"):
print("not matching works")
# ab: third pattern to combine a and b
# first question: is this possible without making a new js_regex?
ab = js_regex.compile(r"^[A-Z]{2}[A-Z0-9]{9}[0-9]||$[A-Z]{3}$")
if ab.match("BE46138E7195"):
print("match ab")
if ab.match("$USD"):
print("match ab")
if not ab.match("BDDD"):
print("not matching works")
So as you can see, 2 regexes and already a first question (see snippet).
But the main question. Suppose I have a list of strings:
["BED", "KLO", "BN"]
I want to check if ALL strings in that list are matching with my ab regex.
BUT: it is ok if they are ALL not matching, like:
["A", "B", "C"]
is ok, because they are all not matching. So I have 2 groups that are possible:
[AB] and [not AB].
What's the best way to tackle this?
Per each of the strings check (the AB check) I would go this way:
if a.match(txt) and b.match(txt):
print("We have a match!")
Now, if you want to check if whole list matches:
def ab_match(txt):
return a.match(txt) and b.match(txt)
list_res = [ab_match(txt) for txt in alist]
all_match = all(list_res)
all_no_match = all((not res for res in list_res))
How does it work:
all - returns True only if all of the values in the iterator have Boolean value of True
So, in case of checking if none of the strings are matching you have to first revert the result per each alist list element.
Separate question if you can combine both regexes. Essentially, you can: for regex A or B you can construct a regex A|B. Typically, (A)|(B) to ensure that the alternative is between the whole regexes not parts of them.
Your ab pattern is wrong, you have a || inside that allows an empty string match, you need just one | to define an alternation.
Next, you did not group the patterns correctly, you need to wrap the p1|p2 with ^(?:p1|p2)$.
So, if you wanted to declare ab pattern you would use
ab = js_regex.compile(r"^(?:[A-Z]{2}[A-Z0-9]{9}[0-9]|\$[A-Z]{3})$")
You can use this pattern like this:
def validate(arr):
return (all(map(ab.search, arr)) or all(map(lambda x: not ab.search(x), arr)) )
See the Python demo:
import js_regex, re
a = js_regex.compile(r"^[A-Z]{2}[A-Z0-9]{9}[0-9]$")
b = js_regex.compile(r"^\$[A-Z]{3}$")
ab = re.compile(f'{a.pattern}|{b.pattern}') # Build the ab pattern from the two above
def validate(arr):
return (all(map(ab.search, arr)) or all(map(lambda x: not ab.search(x), arr)) )
l1 = ["BED", "KLO", "BN"]
l2 = ["A", "B", "C"]
l3 = ["xxx", "$AUD"]
l4 = ['XX46434G8630', '$USD', 'XX46434V7047']
print(validate(l1), validate(l2), validate(l3), validate(l4), sep="\n")
Output:
True
True
False
True
Beginner here, and haven't found an answer for this question though some are similar.
If I have two strings:
s1 = 'abcdefghijk'
s2 = 'abcdefghi'
How do I get 'jk' as an output? 'abcdefghi' must first match, and then I get the difference on the end.
The next after this (which I may be able to figure out if I get the first question answered) is what if s2 = 'cdefghi' and I still want output to be only 'jk' not 'ab' and 'jk'.
You can find the first index of s2 in s1 with find(), i.e.:
def after(s1, s2):
index = s1.find(s2)
# return None if s2 is not part of s1
# or if there are no characters behind s2 in s1
if index != -1 and index + len(s2) < len(s1):
return s1[index + len(s2):]
else:
return None
s1 = "abcdefghijk"
s2 = "cdefghij"
print(after(s1, s2))
For the first case, case s1 = 'abcdefghijk' s2 = 'abcdefghi' , the below would work too.
>>> set(s1) - set(s2)
{'j', 'k'}
>>> ''.join( set(s1) - set(s2))
'jk'
So basically set logic can be applied on strings to extract overlapping and non-overlapping parts of the mentioned strings.
For more info ... https://docs.python.org/2/library/sets.html
But for the 2nd case , #user3760780 suggestion seems to be the best fit.
You can use the string method index to find the start of the substring, then add the length of the substring to get where you want to start taking your extra difference from.
base = 'abcdefghijk'
sub = 'abcdefghi'
def extra(base, sub):
start = base.index(sub)
end = start + len(sub)
return base[end:]
extra(base, sub)
A ValueError will be thrown here if sub is not a substring, and you can choose to do what you wish in that case.
Edit: based on your comment on your question, to return nothing - I'm guessing you mean maybe an empty string - do:
def diff(base, sub):
try:
start = base.index(sub)
end = start + len(sub)
return base[end:]
except ValueError:
return ''
Whether you use find or index here probably depends on what you're actually wanting to use this for.
I have two strings like s1='fly,dream';s2='dream,fly'
I want the s1 equals to s2.
The code I tried is:
def Isequal(m,n):
s1=m.split(',') s2=n.split(',') s1.sort() s2.sort()
if s1 == s2:
print 'Equal'
else:
print s1,s2
Note:s1 may be equal to s2.
Then
def Isequal(m,n):
s1=m.split(',')
s2=n.split(',')
if s1 == s2.reverse() || s1 == s2:
print 'Equal'
else:
print s1,s2
Is this code right? I there something to improve?
Your code splits the two strings by , (which returns a list) and calls the sort method on the list. Since the two substrings are identical, sorting the list of the substrings results in equal lists. The best way to know what is happening is printing the stuff out. See the results.
>>> s1 = 'fly,dream'
>>> s2 = 'dream,fly'
>>> s1 = s1.split(',')
>>> s1
['fly', 'dream']
>>> s2 = s2.split(',')
>>> s2
['dream', 'fly']
>>> s1.sort()
>>> s1
['dream', 'fly']
>>> s2.sort()
>>> s2
['dream', 'fly']
>>> s1 == s2
True
If you want to check that the two strings consist of the same substrings, use sets, like follows :
>>> varOne = set(s1.split(','))
>>> varTwo = set(s2.split(','))
>>> varOne == varTwo
True
Beware that sets only allow unique items, so fly,dream,fly and dream,dream,fly will result in True here.
Set would be more elegant here:
def Isequal(m, n):
s1 = set(m.split(','))
s2 = set(n.split(','))
if s1 == s2:
print 'Equal'
else:
print s1, s2
and should be more efficient too.
You probably don't want to use sort() to flip a list. The sorting that takes place entirely depends on the string (it varies on the first letter of each string). You can use .reverse to reverse a list:
def Isequal(m,n):
m = m.split(',')
m.reverse()
if m == n.split(','):
print "Equal"
else:
print m, n
If you want to sort the list in place, you can always do .reverse() instead of .sort()
If reversing the list was just an example in your question, and your strings would actually have more items when you split them, you can use sets:
def Isequal(m,n):
if not set(m.split(',')).symmetric_difference(n.split(',')):
print "Equal"
else:
print m, n
By the way, Sparse is better than dense.. The semi-colons are rather... ugly.
This question already has answers here:
Changing one character in a string
(15 answers)
Closed last month.
I would like to read some characters from a string s1 and put it into another string s2.
However, assigning to s2[j] gives an error:
s2[j] = s1[i]
# TypeError: 'str' object does not support item assignment
In C, this works:
int i = j = 0;
while (s1[i] != '\0')
s2[j++] = s1[i++];
My attempt in Python:
s1 = "Hello World"
s2 = ""
j = 0
for i in range(len(s1)):
s2[j] = s1[i]
j = j + 1
The other answers are correct, but you can, of course, do something like:
>>> str1 = "mystring"
>>> list1 = list(str1)
>>> list1[5] = 'u'
>>> str1 = ''.join(list1)
>>> print(str1)
mystrung
>>> type(str1)
<type 'str'>
if you really want to.
In Python, strings are immutable, so you can't change their characters in-place.
You can, however, do the following:
for c in s1:
s2 += c
The reasons this works is that it's a shortcut for:
for c in s1:
s2 = s2 + c
The above creates a new string with each iteration, and stores the reference to that new string in s2.
assigning to s2[j] gives an error
Strings are immutable so what you've done in C won't be possible in Python. Instead, you'll have to create a new string.
I would like to read some characters from a string and put it into
other string.
Use a slice:
>>> s1 = 'Hello world!!'
>>> s2 = s1[6:12]
>>> print(s2)
world!
Strings in Python are immutable (you cannot change them inplace).
What you are trying to do can be done in many ways:
Copy the string:
foo = 'Hello'
bar = foo
Create a new string by joining all characters of the old string:
new_string = ''.join(c for c in oldstring)
Slice and copy:
new_string = oldstring[:]
Performant methods
If you are frequently performing index replacements, a more performant and memory-compact method is to convert to a different data structure. Then, convert back to string when you're done.
list:
Easiest and simplest:
s = "TEXT"
s = list(s)
s[1] = "_"
s = "".join(s)
bytearray (ASCII):
This method uses less memory. The memory is also contiguous, though that doesn't really matter much in Python if you're doing single-element random access anyways:
ENC_TYPE = "ascii"
s = "TEXT"
s = bytearray(s, ENC_TYPE)
s[1] = ord("_")
s = s.decode(ENC_TYPE)
bytearray (UTF-32):
More generally, for characters outside the base ASCII set, I recommend using UTF-32 (or sometimes UTF-16), which will ensure alignment for random access:
ENC_TYPE = "utf32"
ENC_WIDTH = 4
def replace(s, i, replacement):
start = ENC_WIDTH * (i + 1)
end = ENC_WIDTH * (i + 2)
s[start:end] = bytearray(replacement, ENC_TYPE)[ENC_WIDTH:]
s = "TEXT HI ひ RA ら GA が NA な DONE"
s = bytearray(s, ENC_TYPE)
# Performs s[1] = "_"
replace(s, 1, "_")
s = s.decode(ENC_TYPE)
Though this method may be more memory-compact than using list, it does require many more operations.
Other answers convert the string to a list or construct a new string character by character. These methods can be costly, especially for large strings. Instead, we can use slicing to get the parts of the string before and after the character that is changed, and combine those with the new character.
Here I modify the example code from Crowman's answer to replace a single character in the string using string slicing instead of conversion to a list.
>>> str1 = "mystring"
>>> pos = 5
>>> new_char = 'u'
>>> str2 = str1[:pos] + new_char + str1[pos+1:]
>>> print(str2)
mystrung
>>> type(str2)
<class 'str'>
Another approach if you wanted to swap out a specific character for another character:
def swap(input_string):
if len(input_string) == 0:
return input_string
if input_string[0] == "x":
return "y" + swap(input_string[1:])
else:
return input_string[0] + swap(input_string[1:])
The 'str' is an immutable data type. Therefore str type object doesn't support item assignment.
s1 = "Hello World"
s2 = ['']*len(s1)
j = 0
for i in range(len(s1)):
s2[j]=s1[i]
j = j + 1
print(''.join(s2)) # Hello World
How about this solution:
str="Hello World" (as stated in problem)
srr = str+ ""
Hi you should try the string split method:
i = "Hello world"
output = i.split()
j = 'is not enough'
print 'The', output[1], j