find all possible rotation of a given string using python - python

Given string is "abc" then it should print out "abc", "bca", "cba"
My approach: find length of the given string and rotate them till length
def possible_rotation():
a = "abc"
b = len(a)
for i in range (b-1):
c = a[:i] + a[i:]
print c
Above code simply prints abc, abc. Any idea what am I missing here?

def possible_rotation():
a = "abc"
b = len(a)
for i in range (b):
c = a[i:]+a[:i]
print c
possible_rotation()
Output:
abc
bca
cab
You have 2 issues.The range issue and the rotation logic.it should be a[i:]+a[:i] not the other way round.For range range(b-1) should be range(b)

You have two errors:
range(b-1) should be range(b);
a[:i] + a[i:] should be a[i:] + a[:i].

This is what I did. I used a deque, A class in collections and then used the rotate function like this
from collections import deque
string = 'abc'
for i in range(len(string)):
c = deque(string)
c.rotate(i)
print ''.join(list(c))
And gives me this output.
abc
cab
bca
What it does. It creates a deque object, A double ended queue object, which has a method rotate, rotate takes the number of steps to rotate and returns the objects shifted to the right with the number of steps kinda like rshift in binary operations. Through the loops it shifts ad produces a deque object that I convert to list and finally to a string.
Hope this helps

for i in range(b):
print(a[i:] + a[:i])
0 - [a,b,c] + []
1 - [b,c] + [a]
2 - [c ] + [a,b]
swap the lists

No need to do (b-1),You simply do it by:
def possible_rotation():
a = "abc"
for i in range(0,len(a)):
strng = a[i:]+a[:i]
print strng
possible_rotation()
`

This looks to be homework, but here's a solution using the built-in collections.deque:
from collections import deque
def possible_rotations(string):
rotated = deque(string)
joined = None
while joined != string:
rotated.rotate(1)
joined = ''.join(x for x in rotated)
print(joined)
Test it out:
>>> print(possible_rotations('abc'))
cab
bca
abc

Two things:
Firstly, as already pointed out in the comments, you should iterate over range(b) instead of range(b-1). In general, range(b) is equal to [0, 1, ..., b-1], so in your example that would be [0, 1, 2].
Secondly, you switched around the two terms, it should be: a[i:] + a[:i].

Related

how to remove python list cage

Like this, let's assume I have a script like this:
a = ['a','b','c','d','e']
b = random.choices(a)
print (b)
if you run that that will show like this right
['*random range a until e']
what I want the list change from this ['*random range a until e'] to '*random range a until we' can anyone help me
random.choices(), returns a LIST, as you can read here - https://www.w3schools.com/python/ref_random_choices.asp
So workaround would be to do it like this:
import random
a = ['a','b','c','d','e']
n = random.randint(0, len(a) - 1) # The randint() takes in 2 parameters, the
#lowest and the highest choice, the highest here is the length of a list
b = a[n]
print(b)
You need to join the letters obtained from random.choices.
With the argument k=<size> you can specify the length of the generated string.
>>> import random
>>> a = ['a','b','c','d','e']
>>> size = 10
>>> b = "".join(random.choices(a, k=size))
>>> b
'caccbbaade'

Concatenate List in Python

I have 3 list's which are having one value i want to concatenate the list, so i used + operator to concatenate but the output is not what i expected. I need to use the list because in some cases i can get more results instead of one.
Lists:
A = ["F"]
B = ["SZLY"]
C = ["RQTS"]
D = ["19230711"]
Output:
['F']['SZLY']['RQTS']['19230711']
Expected Output:
FSZLYRQTS19230711
Update:
I used below code to concatenate. I used str() because i want to cast the topmost list element to string.
hrk = str(A)+str(B)+str(C)+str(D)
How can i get the expected output.
str on a list prints a representation of the list (for debug purposes). It's bad to process that as string further in your code.
most pythonic way: use join in a list comprehension for first & only item of your lists
A = ["F"]
B = ["SZLY"]
C = ["RQTS"]
D = ["19230711"]
print(["".join(x[0] for x in (A,B,C,D))])
results in:
FSZLYRQTS19230711
Try like this,
In [32]: A[0]+B[0]+C[0]+D[0]
Out[32]: 'FSZLYRQTS19230711'
Try:
A[0] + B[0] + C[0] + D[0]
You are trying to access first element of list so you have to access them by index.
What you are currently doing will create a single list with all the elements. Like:
A = ['2414214']
B = ['fefgg']
C = A + B
print C
# Will print
['2414214', 'fefgg']

Repeating characters results in wrong repetition counts

My function looks like this:
def accum(s):
a = []
for i in s:
b = s.index(i)
a.append(i * (b+1))
x = "-".join(a)
return x.title()
with the expected input of:
'abcd'
the output should be and is:
'A-Bb-Ccc-Dddd'
but if the input has a recurring character:
'abccba'
it returns:
'A-Bb-Ccc-Ccc-Bb-A'
instead of:
'A-Bb-Ccc-Cccc-Bbbbb-Aaaaaa'
how can I fix this?
Don't use str.index(), it'll return the first match. Since c and b and a appear early in the string you get 2, 1 and 0 back regardless of the position of the current letter.
Use the enumerate() function to give you position counter instead:
for i, letter in enumerate(s, 1):
a.append(i * letter)
The second argument is the starting value; setting this to 1 means you can avoid having to + 1 later on. See What does enumerate mean? if you need more details on what enumerate() does.
You can use a list comprehension here rather than use list.append() calls:
def accum(s):
a = [i * letter for i, letter in enumerate(s, 1)]
x = "-".join(a)
return x.title()
which could, at a pinch, be turned into a one-liner:
def accum(s):
a = '-'.join([i * c for i, c in enumerate(s, 1)]).title()
This is because s.index(a) returns the first index of the character. You can use enumerate to pair elements to their indices:
Here is a Pythonic solution:
def accum(s):
return "-".join(c*(i+1) for i, c in enumerate(s)).title()
simple:
def accum(s):
a = []
for i in range(len(s)):
a.append(s[i]*(i+1))
x = "-".join(a)
return x.title()

Strings of two letters and fixed length

I'm wondering how to generate a list of all possible two-letter strings of length 10 in Python. For example, the list would go:
aaaaaaaaaa
aaaaaaaaab
aaaaaaaaba
aaaaaaaabb
...
...
...
bbbbbbbbab
bbbbbbbbba
bbbbbbbbbb
Also, I'm aware of how naive my question might be; I'm still in the learning process.
from itertools import product
prod = [''.join(p) for p in product('ab', repeat=10)]
or if you just want to print it like in your example:
from itertools import product
for p in product('ab', repeat=10):
print(''.join(p))
See the documentation for itertools.product
You can count from 0 to 2**10-1, convert those numbers using bin and replace 0/1 with a/b. Just pad the left side with 0's to the right length.
def s(d):
if d:
for c in 'ab':
for rest in s(d-1):
yield c + rest
else:
yield ''
print list(s(10))
or
def x(d):
return ([ 'a' + q for q in x(d-1) ] +
[ 'b' + q for q in x(d-1) ]) if d else [ '' ]
print x(10)

Longest common prefix using buffer?

If I have an input string and an array:
s = "to_be_or_not_to_be"
pos = [15, 2, 8]
I am trying to find the longest common prefix between the consecutive elements of the array pos referencing the original s. I am trying to get the following output:
longest = [3,1]
The way I obtained this is by computing the longest common prefix of the following pairs:
s[15:] which is _be and s[2:] which is _be_or_not_to_be giving 3 ( _be )
s[2:] which is _be_or_not_to_be and s[8:] which is _not_to_be giving 1 ( _ )
However, if s is huge, I don't want to create multiple copies when I do something like s[x:]. After hours of searching, I found the function buffer that maintains only one copy of the input string but I wasn't sure what is the most efficient way to utilize it here in this context. Any suggestions on how to achieve this?
Here is a method without buffer which doesn't copy, as it only looks at one character at a time:
from itertools import islice, izip
s = "to_be_or_not_to_be"
pos = [15, 2, 8]
length = len(s)
for start1, start2 in izip(pos, islice(pos, 1, None)):
pref = 0
for pos1, pos2 in izip(xrange(start1, length), xrange(start2, length)):
if s[pos1] == s[pos2]:
pref += 1
else:
break
print pref
# prints 3 1
I use islice, izip, and xrange in case you're talking about potentially very long strings.
I also couldn't resist this "One Liner" which doesn't even require any indexing:
[next((i for i, (a, b) in
enumerate(izip(islice(s, start1, None), islice(s, start2, None)))
if a != b),
length - max((start1, start2)))
for start1, start2 in izip(pos, islice(pos, 1, None))]
One final method, using os.path.commonprefix:
[len(commonprefix((buffer(s, n), buffer(s, m)))) for n, m in zip(pos, pos[1:])]
>>> import os
>>> os.path.commonprefix([s[i:] for i in pos])
'_'
Let Python to manage memory for you. Don't optimize prematurely.
To get the exact output you could do (as #agf suggested):
print [len(commonprefix([buffer(s, i) for i in adj_indexes]))
for adj_indexes in zip(pos, pos[1:])]
# -> [3, 1]
I think your worrying about copies is unfounded. See below:
>>> s = "how long is a piece of string...?"
>>> t = s[12:]
>>> print t
a piece of string...?
>>> id(t[0])
23295440
>>> id(s[12])
23295440
>>> id(t[2:20]) == id(s[14:32])
True
Unless you're copying the slices and leaving references to the copies hanging around, I wouldn't think it could cause any problem.
edit: There are technical details with string interning and stuff that I'm not really clear on myself. But I'm sure that a string slice is not always a copy:
>>> x = 'google.com'
>>> y = x[:]
>>> x is y
True
I guess the answer I'm trying to give is to just let python manage its memory itself, to begin with, you can look at memory buffers and views later if needed. And if this is already a real problem occurring for you, update your question with details of what the actual problem is.
One way of doing using buffer this is give below. However, there could be much faster ways.
s = "to_be_or_not_to_be"
pos = [15, 2, 8]
lcp = []
length = len(pos) - 1
for index in range(0, length):
pre = buffer(s, pos[index])
cur = buffer(s, pos[index+1], pos[index+1]+len(pre))
count = 0
shorter, longer = min(pre, cur), max(pre, cur)
for i, c in enumerate(shorter):
if c != longer[i]:
break
else:
count += 1
lcp.append(count)
print
print lcp

Categories

Resources