Making a string by reading down a matrix 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) -&gt; 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) -&gt; 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:       |       Avg
Permute: (10,000 loops, best of 10):     0.43404            0.44310
Unpermute: (10,000 loops, best of 10):   0.37202            0.38102

n = 1024                                  Best:       |       Avg
Permute: (10,000 loops, best of 10):     1.82779            1.85647
Unpermute: (10,000 loops, best of 10):   1.72195            1.78491
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))))