2

a flat (one dimension) tuple on input:

data = ('a','b','c'.....'z');

output: table (two dimensions) that has n (say 9) columns

table = ?what code here?

so

print table
 ( ('a','b','c'...), ('k','l','m','n'...), ....)

which is the shortest way to do so?

vasq
  • 51
  • 1
  • 5
  • related: [What is the most "pythonic" way to iterate over a list in chunks?](http://stackoverflow.com/q/434287/) – jfs Sep 08 '11 at 04:47

5 Answers5

7

Here's the short version if you find the rest of this too wordy:

n = 9
table = zip(*[iter(data)]*n)

Let's say you start with a list:

>>> data = range(1,101)
>>> data
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,
99, 100]

Create an iterator for your list:

>>> data_iter = iter(data)

Now use the zip function to split up the list. Pay attention, this is the fun part!

>>> table = zip(*[data_iter]*9)
>>> pprint.pprint(table)
[(1, 2, 3, 4, 5, 6, 7, 8, 9),
 (10, 11, 12, 13, 14, 15, 16, 17, 18),
 (19, 20, 21, 22, 23, 24, 25, 26, 27),
 (28, 29, 30, 31, 32, 33, 34, 35, 36),
 (37, 38, 39, 40, 41, 42, 43, 44, 45),
 (46, 47, 48, 49, 50, 51, 52, 53, 54),
 (55, 56, 57, 58, 59, 60, 61, 62, 63),
 (64, 65, 66, 67, 68, 69, 70, 71, 72),
 (73, 74, 75, 76, 77, 78, 79, 80, 81),
 (82, 83, 84, 85, 86, 87, 88, 89, 90),
 (91, 92, 93, 94, 95, 96, 97, 98, 99)]

The expression `[data_iter]*9' results in the following list:

[ data_iter, data_iter, data_iter, data_iter, data_iter, 
data_iter, data_iter, data_iter, data_iter ]

The expresion *[data_iter]*9 turns this into nine arguments to the zip function. This zip function builds a list of tuples:

Return a list of tuples, where each tuple contains the i-th element from each of the argument sequences. The returned list is truncated in length to the length of the shortest argument sequence.

Because we're using an iterator, every time zip function looks for a new value it gets the next value in the sequence. Contrast this with the behavior if we had simply used a list the same way:

>>> table = zip(*[data]*9)
>>> pprint.pprint(table)
[(1, 1, 1, 1, 1, 1, 1, 1, 1),
 (2, 2, 2, 2, 2, 2, 2, 2, 2),
 (3, 3, 3, 3, 3, 3, 3, 3, 3),
 ...
 (99, 99, 99, 99, 99, 99, 99, 99, 99),
 (100, 100, 100, 100, 100, 100, 100, 100, 100)]

UPDATE: My colleague points out that if you have NumPy available, you can do this:

>>> data = numpy.array(range(1,101))
>>> data.reshape([10,10])
array([[  1,   2,   3,   4,   5,   6,   7,   8,   9,  10],
   [ 11,  12,  13,  14,  15,  16,  17,  18,  19,  20],
   [ 21,  22,  23,  24,  25,  26,  27,  28,  29,  30],
   [ 31,  32,  33,  34,  35,  36,  37,  38,  39,  40],
   [ 41,  42,  43,  44,  45,  46,  47,  48,  49,  50],
   [ 51,  52,  53,  54,  55,  56,  57,  58,  59,  60],
   [ 61,  62,  63,  64,  65,  66,  67,  68,  69,  70],
   [ 71,  72,  73,  74,  75,  76,  77,  78,  79,  80],
   [ 81,  82,  83,  84,  85,  86,  87,  88,  89,  90],
   [ 91,  92,  93,  94,  95,  96,  97,  98,  99, 100]])
larsks
  • 277,717
  • 41
  • 399
  • 399
2

How about this:

table = tuple(data[n:n+9] for n in xrange(0,len(data),9))

Returns a tuple made from stepping through data 9 items at a time. If you want to change the number of columns, just change both nines in the generator

  • When I use timeit to time your solution and larsks solution, yours seems to be faster. 1,000,000 calls yields a total of 4.43 for yours and 5.02 for his (I could also be doing something wrong). – djhoese Sep 08 '11 at 01:36
  • It's possible that list comprehensions are faster than function calls. I just think iterators are nifty. – larsks Sep 08 '11 at 01:44
  • Well, I just used `cProfile` to time them. @larsks is actually twice as fast, it seems. Also, only four function calls versus my 100004 (for a 90000 item tuple). – Hod - Monica's Army Sep 08 '11 at 01:45
  • I only did a couple tries on each, so no average times, but from how many I did do it looks pretty consistent: about 75% - 100% for @larsks method. Pity, I thought mine was pretty good. – Hod - Monica's Army Sep 08 '11 at 01:51
0

I'm surprised this isn't in itertools, but it doesn't seem to be. Here's my approach:

def segment_list(lst, step):
    """
    Segment lst into a list of step-length lists
    """
    segments = []
    while True:
        if len(lst) <= step:
            output.append(lst)
            break
        output.append(lst[0:step])
        lst = lst[step+1:]
    return segments
Daenyth
  • 35,856
  • 13
  • 85
  • 124
0
>>> n = 3
>>> data = ('a', 'b', 'c', 'd', 'e', 'f',
...        'g', 'h', 'i', 'j', 'k', 'l',
...        'm', 'n')

>>> table = []    

>>> for i in xrange( 0, divmod( len(data), n)[0] + 1):
...     table.append( data[i*n:i*n+n] )

>>> print tuple( table )
(('a', 'b', 'c'), ('d', 'e', 'f'), ('g', 'h', 'i'), ('j', 'k', 'l'), ('m', 'n'))
gsbabil
  • 7,505
  • 3
  • 26
  • 28
0

Daenth,

The zip method described by larsks (above) is described in the itertools module documentation - search for "grouper" among the recipes:

richardw
  • 728
  • 5
  • 9