HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Making a string by reading down a matrix

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
readingdownmakingmatrixstring

Problem

Suppose I have a string with a length always a multiple of four:

'CodeReviewSE'


My goal is to create a permutation. First, I arrange the string into a matrix (where each row has a length of 4):

C o d e
R e v i
e w S E


And then I simply read down, starting from the top-left corner. I get four segments: CRe, oew, dvs and eiE. I concatenate them, to get the following string:

'CReoewdvSeiE'


Reversing the operation is just reversing the steps, kinda. It follows the same steps, except for row length are len(text) / 4, and we read down again, to look like this:

C R e
o e w
d v S
e i E


I've implemented the following code in Python:

import collections

def permute(text):
# type: (str) -> str

rows = collections.deque()
output = ''

# Create matrix
for i in xrange(0, len(text), 4):
rows.append(text[i:i+4])

# Read matrix downwards
for counter in xrange(4):
for row in rows:
output += row[counter]

return output

def unpermute(text):
# type: (str) -> str

rows = collections.deque()
output = ''
length = len(text) / 4

# Create matrix
for i in xrange(0, len(text), length):
rows.append(text[i:i+length])

# Now read downwards
for counter in xrange(length):
for row in rows:
output += row[counter]

return output


I also ran a performance tests using the timeit module, using random strings of different lengths (where n is the length):

`n = 32 Best: | Avg
Permute: (10,000 loops, best of 10): 0.06563 0.07080
Unpermute: (10,000 loops, best of 10): 0.06337 0.06655

n = 64 Best: | Avg
Permute: (10,000 loops, best of 10): 0.11592 0.11939
Unpermute: (10,000 loops, best of 10): 0.10358 0.10530

n = 256 Best:

Solution

Most important comment: permute is just unpermute with length = 4.

There seems to be no reason to favor collections.deque over a normal list here. It is only an advantage of you do a lot of queue.popleft() calls.

For the creation of rows you can just use a list comprehension:

rows = (text[i:i+4] for i in xrange(0, len(text), 4))


I would use a generator expression here to save memory

You could simplify your un-/permute to: something like:

def permute(text, n=4, reverse=False):
    n = len(text)/n if reverse else n
    matrix = (text[i:i+n] for i in range(0, len(text), n))
    matrix_t = zip(*matrix)
    return "".join("".join(x) for x in matrix_t)


where (text[i:i+n] for i in range(0, len(text), n)) makes a generator object that is like your rows, zip(*list) transposes a list of lists and the two joins first join each row and then the rows.

This will not even create a lot of overhead because they are all generator objects (and therefore it is not one possibly big list being read into memory).

You could even inline all of it:

def permute(text, n):
    return "".join("".join(x) for x in zip(*(text[i:i+n] for i in range(0, len(text), n))))

Code Snippets

rows = (text[i:i+4] for i in xrange(0, len(text), 4))
def permute(text, n=4, reverse=False):
    n = len(text)/n if reverse else n
    matrix = (text[i:i+n] for i in range(0, len(text), n))
    matrix_t = zip(*matrix)
    return "".join("".join(x) for x in matrix_t)
def permute(text, n):
    return "".join("".join(x) for x in zip(*(text[i:i+n] for i in range(0, len(text), n))))

Context

StackExchange Code Review Q#140171, answer score: 3

Revisions (0)

No revisions yet.