def isRotation(s1, s2):
return len(s1) == len(s2) and s2 in s1*2
isRotation("ABCD", "CDAB")
>> True
The code above was given as one of many ways to check if two strings are a rotation of each other.
However, I don't understand why String1(s1) has to be multiplied by 2 in the code.
In python, multiplying strings is repeating the string, for example:
>>> 'abc'*2
'abcabc'
>>> 'abc'*4
'abcabcabcabc'
So in order to know if a string is a rotation of another string, you would need to multiplie it by 2, for example:
>>> 'bca' in 'abc'
False
>>> 'bca' in 'abc' * 2
True
Multiplying a string by 2 will double the original string. And because s1 wraps around, regardless of its starting position the whole string can be found somewhere within twice its length
ABCDABCD
|||| DABC
||| CDAB
|| BCDA
| ABCD
Rotating a string is as good as chopping it at point of rotation and putting that chopped part at the end of string.
ABCDEFGH rotated 4 places to left is:
Chop at 4-> ABCD EFGH
Place at the end -> EFGHABCD
Python str*x gives you str concatenated to itself x times.
>>> a = 'String'
>>> a*2
'StringString'
>>>
Putting these two points together with the fact that any string can be rotated by maximum amount equal to its length (when it becomes the original string) gives you the logic to check the rotated string's presence in str*2.
Understanding of your question is- To compare a string with the rotation string.
My approach to address the same would be.
1- To get the rotation string.
def rotate_str(strg, n):
return strg[n:] + strg[:n]
length = 2 #can change this to whatever value suits to you or even pass this as arg.
print(rotate('SAMPLE', length))
2- compare strings.
str1 = 'SAMPLE'
str2 = rotate(str1, length)
def compare_str(str1, str2):
return str1 == str2
Here when we multiply s1 with 2. It returns s1s1 like if s1="ABCD", it will return "ABCDABCD", and in if s2 in s1*2 we are checking that if "CRAB" is in "ABCDABCD" which is true.
Related
I'm interested in how is Python handling slicing where the stop attribute is larger than the length of the string we are working with, for example:
my_string = 'abc'
my_slice = my_string[:10]
I am aware that my_slice == 'abc', what interests me is how efficient this is and how it works under the hood.
I've read Time complexity of string slice and Understanding slice notation, but didn't find the exact case I was looking for.
My guess based on mentioned sources would be that a shallow copy of the string is returned (my_string[:10] is the same as my_string[:] in this case), is this the case?
The logic of python is that it will extract all the values that are before that index in the list.
So if the stop value is higher than the length of the list it will return the whole list because all the values' indexes are under the stop number, so it will extract all the values.
Slicing in Python follows the following format:
myVar[fromIndex:toIndex]
The end of the slicing marked by the toIndex, counts to its index, which is one character less:
my_string = 'abc'
print(my_string[2]) #Output: 'c'
print(my_string[:2]) #Output: 'ab'
If we set a final index greater than the length of characters of the data, it will take it entire (it prints from the first value to the last one found). For example (following the example you have given):
0 1 2 3
a b c
my_string = 'abc'
print(my_string[:len(my_string)]) #Output: 'abc'
With the following example, you can clearly see that [:] (being the full length of the string) is equivalent to printing the value by slicing from the beginning to the end of the string:
0 1 2
a b c
my_string = 'abc'
print(my_string[:]) #Output: 'abc'
0 1 2 3
a b c
my_string = 'abc'
print(len(my_string)) #Output: '3'
print(my_string[:len(my_string)]) #Output: 'abc'
How would you go about splitting a normal string in to as many identical pieces as possible whilst using all characters. For example
a = "abab"
Would return "ab", whereas with
b= "ababc"
It would return "ababc", as it can't be split into identical pieces using all letters.
This is very similar, but not identical, to How can I tell if a string repeats itself in Python? – the difference being that that question only asks to determine whether a string is made up of identical repeating substrings, rather than what the repeating substring (if any) is.
The accepted (and by far the best performing) answer to that question can be adapted to return the repeating string if there is one:
def repeater(s):
i = (s+s)[1:-1].find(s)
if i == -1:
return s
else:
return s[:i+1]
Examples:
>>> repeater('abab')
'ab'
>>> repeater('ababc')
'ababc'
>>> repeater('xyz' * 1000000)
'xyz'
>>> repeater('xyz' * 50 + 'q')
'xyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzq'
It seems that repeating substring has no pre and after letters, so it also could be this way:
In[4]: re.sub(r'^([a-z]+)\1$',r'\1','abab')
Out[4]: 'ab'
In[5]: re.sub(r'^([a-z]+)\1$',r'\1','ababc')
Out[5]: 'ababc'
([a-z]+) means substring, \1 means repeat.
EDIT :
re.sub(r'^([a-z]+)\1{1,}$',r'\1','abcabcabcabc')
'abc'
Simple script to find if the second arguement appears 3 times successively in the first arguement. I am able to find if the second arguement is in first and how many time etc but how do i see if its present 3 times successively or not ?
#!/usr/bin/python
import string
def three_consec(s1,s2) :
for i in s1 :
total = s1.count(s2)
if total > 2:
return "True"
print three_consec("ABABA","A")
total = s1.count(s2) will give you the number of s2 occurrences in s1 regardless of your position i.
Instead, just iterate through the string, and keep counting as you see characters s2:
def three_consec (string, character):
found = 0
for c in string:
if c == character:
found += 1
else:
found = 0
if found > 2:
return True
return False
Alternatively, you could also do it the other way around, and just look if “three times the character” appears in the string:
def three_consec (string, character):
return (character * 3) in string
This uses the feature that you can multiplicate a string by a number to repeat that string (e.g. 'A' * 3 will give you 'AAA') and that the in operator can be used to check whether a substring exists in a string.
I am looking at adding numbers to a string as python reads through a string.
So if I had a string a = "253+"
I would then have an empty string b.
So, how would I have python read the 2, add it to string b, then read the 5 and add it to string b, and then add the 5 and add it to string b, when it hits something that isnt an integer though, it stops the function.
then string b would be b = "253"
is there a specific call in an iteration that would ask for integers and then add i to another string?
tl;dr
I want to use an iteration to add numbers from one string to another, which stops when it reaches a non-integer.
string b would be an empty string, and string a would be a="253+"
after the call would be done, strng b would equal b="253"
I know this sounds like a homework question, but its not. If you need anything else clarified, I would be happy to.
Here is a simple method for extracting the digits from a string:
In [13]: a="253+"
In [14]: ''.join(c for c in a if c.isdigit())
Out[14]: '253'
The question is a bit unclear, but is this what you're looking for?
a = "123+"
b=""
for c in a:
try:
int(c)
b = b + c
except ValueError:
print 'This is not an int ' + c
break
Running this results in this b being 123 and breaking on the + character. It sounds like the part that's tricky for you at the moment is the try..except ValueError bit. Not that I don't have to break the loop when a ValueError happens, I could just keep looping over the remaining characters in the string and ignore ones that cannot be parsed into an int
In [201]: import itertools as IT
In [202]: a = "253+9"
In [203]: ''.join(IT.takewhile(str.isdigit, a))
Out[203]: '253'
IT.takewhile will stop at the first character in a which is not a digit.
Another way would be to use a regex pattern. You could split the string on non-digits using the pattern r'\D':
In [208]: import re
In [209]: re.split(r'\D', a, maxsplit=1)[0]
Out[209]: '253'
With the use of the for loop, this is relatively easy. If we use our ASCII knowledge, we know that the ASCII values of the digits range from 48 (which represents 0 as a string) to 57 (which represents 9 as a string).
We can find the ASCII value of a character by using the built in method ord(x) where x is the character (i.e. ord('4') is equal to 52, the integer).
Now that we have this knowledge, it will be easy to add this to our for-loop. We simply make a for-loop that goes from 0 to the length of the string minus 1. In the for loop, we are going to use the iteration that we are on as an index, find the character at that index in our string, and finally check to see if its ord value falls in the range that we want.
This will look something like this:
def method(just_a_variable):
b = ''
for i in range(0, len(a)):
if (#something):
if (#something):
b = b+a[i]
return b
Can you fill in the "#somethings"?
Try this:
a = "i889i" #Initial value of A
b = "" #Empty string to store result into
for each in a: #iterate through all characters of a
if each.isdigit(): #check if the current character is a digit
b += each #append to b if the current character is a digit
else: #if current character is NOT a digit
break #break out of for loop
print b #print out result
Hope this helps!
You can write a generator with a regex and generate them one by one:
>>> import re
>>> s='123+456abc789'
>>> nums=(m.group(1) for m in re.finditer(r'(\d+)', s))
>>> next(nums)
'123'
>>> next(nums)
'456'
>>> next(nums)
'789'
I have the following problem: I would like to write a function in Python which, given a string, returns a string where every group of two characters is swapped.
For example given "ABCDEF" it returns "BADCFE".
The length of the string would be guaranteed to be an even number.
Can you help me how to do it in Python?
To add another option:
>>> s = 'abcdefghijkl'
>>> ''.join([c[1] + c[0] for c in zip(s[::2], s[1::2])])
'badcfehgjilk'
import re
print re.sub(r'(.)(.)', r'\2\1', "ABCDEF")
from itertools import chain, izip_longest
''.join(chain.from_iterable(izip_longest(s[1::2], s[::2], fillvalue = '')))
You can also use islices instead of regular slices if you have very large strings or just want to avoid the copying.
Works for odd length strings even though that's not a requirement of the question.
While the above solutions do work, there is a very simple solution shall we say in "layman's" terms. Someone still learning python and string's can use the other answers but they don't really understand how they work or what each part of the code is doing without a full explanation by the poster as opposed to "this works". The following executes the swapping of every second character in a string and is easy for beginners to understand how it works.
It is simply iterating through the string (any length) by two's (starting from 0 and finding every second character) and then creating a new string (swapped_pair) by adding the current index + 1 (second character) and then the actual index (first character), e.g., index 1 is put at index 0 and then index 0 is put at index 1 and this repeats through iteration of string.
Also added code to ensure string is of even length as it only works for even length.
string = "abcdefghijklmnopqrstuvwxyz123"
# use this prior to below iteration if string needs to be even but is possibly odd
if len(string) % 2 != 0:
string = string[:-1]
# iteration to swap every second character in string
swapped_pair = ""
for i in range(0, len(string), 2):
swapped_pair += (string[i + 1] + string[i])
# use this after above iteration for any even or odd length of strings
if len(swapped_pair) % 2 != 0:
swapped_adj += swapped_pair[-1]
print(swapped_pair)
badcfehgjilknmporqtsvuxwzy21 # output if the "needs to be even" code used
badcfehgjilknmporqtsvuxwzy213 # output if the "even or odd" code used
Here's a nifty solution:
def swapem (s):
if len(s) < 2: return s
return "%s%s%s"%(s[1], s[0], swapem (s[2:]))
for str in ("", "a", "ab", "abcdefgh", "abcdefghi"):
print "[%s] -> [%s]"%(str, swapem (str))
though possibly not suitable for large strings :-)
Output is:
[] -> []
[a] -> [a]
[ab] -> [ba]
[abcdefgh] -> [badcfehg]
[abcdefghi] -> [badcfehgi]
If you prefer one-liners:
''.join(reduce(lambda x,y: x+y,[[s[1+(x<<1)],s[x<<1]] for x in range(0,len(s)>>1)]))
Here's a another simple solution:
"".join([(s[i:i+2])[::-1]for i in range(0,len(s),2)])