0

I have a list of letters in Python that I would like to split into even-length chunks that will display as rows. For pedagogical reasons, I want to do it without using and libraries (including numpy or Pandas). No, this is not a homework question-- I'm teaching myself.

In R I would be using a vector instead of a list; a simple as.matrix(vector, ncol = n) would do the trick. Is there an equivalent in Python?

As an example, I've tried the following based on other SO answers:

alphabet = map(chr, range(65, 91))
print alphabet
> ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
def chunks(l, n):
    n = max(1, n)
    return [l[i:i + n] for i in range(0, len(l), n)]

print chunks(alphabet, 4)
> [['A ', 'B', 'C', 'D'], ['E', 'F', 'G', 'H'], ['I', 'J', 'K', 'L'], ['M', 'N', 'O', 'P'], ['Q', 'R', 'S', 'T'], ['U', 'V', 'W', 'X'], ['Y', 'Z']]

That generally works, but I would like the output to look like this:

[['A ', 'B', 'C', 'D'], 
['E', 'F', 'G', 'H'], 
['I', 'J', 'K', 'L'], 
['M', 'N', 'O', 'P'], 
['Q', 'R', 'S', 'T'], 
['U', 'V', 'W', 'X'],
 ['Y', 'Z']]

Ideally, I will extend the functionality to make the "most square" rectangle. Ie, I will pull out the highest factors of the length of the list and then use the smaller number as the number of columns, so if possible I want a very generalized answer.

Nancy
  • 3,989
  • 5
  • 31
  • 49

2 Answers2

0

I would define a new function that prints the chunks line by line.

def print_chunks(chunk_result):
    for chunk in chunks:
        print(chunk)

I believe this will give you the output you're looking for.

To get slicing behaviour, you will want to implement your own class. I have quickly whipped out something that should get you started, but I have not checked it thoroughly.

class Chunk(object):
    """docstring for Chunk"""
    def __init__(self, l, n):
        super(Chunk, self).__init__()
        self.chunks = self.chunk(l, n)

    def __repr__(self):
        """
        Done in a non-standard way.
        """
        for chunk in self.chunks:
            print(chunk)

    def __getitem__(self, key):
        if isinstance(key, slice):
            return self.chunks[i] for i in xrange(*key.indices(len(self.chunks)))
        elif isinstance(key, int):
            if key < 0:
                key += len(self.chunks)
            if key >= len(self):
                raise IndexError('The index {0} is out of range'.format(key))
            return self.chunks[i]

For reference, I looked at the following SO posts: Python: Implementing slicing in __getitem__

Community
  • 1
  • 1
ericmjl
  • 13,541
  • 12
  • 51
  • 80
  • Will I be able to index it like an R matrix? For example, will the resulting grid be one object that I can name and slice? – Nancy Feb 14 '15 at 00:54
  • If you want to index it, then `chunks[0]` will return you the first row, `chunks[1]` will return the second row, and so on. However, fancy indexing in the style of `chunks[4,2]` will not be possible, unless you create your own Python class/object that interprets the slicing notation. – ericmjl Feb 14 '15 at 00:56
  • 1
    You seem to be a little confused between the string representation of an object and the object itself. In your example, if you do `result = chunks(alphabet, 4)`, then you can index into the `result` object and slice it etc. The string representation of any object is, well, a string (and so it has properties of strings, not the original object). – Alok-- Feb 14 '15 at 00:56
  • I echo Alok on that. The string representation (i.e. what is displayed to the screen) is different from the underlying data representation itself. – ericmjl Feb 14 '15 at 00:57
  • Okay, that makes sense. I'm definitely want to be able to do fancy indexing like what ericmjl said. This will require defining a new class? – Nancy Feb 14 '15 at 01:06
  • Yes, that is right, Nancy. I can update my answer to give you some pseudocode to get started, but as you mentioned that this is a pedagogical exercise, I will leave the details to you :-). (Disclaimer: none of what I write will be the most efficient; others have implemented libraries that will be a ton more efficient.) – ericmjl Feb 14 '15 at 01:07
0

Just use print each list within:

for line in chunks(alphabet, 4):
    print line
Malik Brahimi
  • 16,341
  • 7
  • 39
  • 70