views:

86

answers:

5

I have a long tuple like

(2, 2, 10, 10, 344, 344, 45, 43, 2, 2, 10, 10, 12, 8, 2, 10)

and i am trying to split it into a tuple of tuples like

((2, 2, 10, 10), (344, 344, 45, 43), (2, 2, 10, 10), (12, 8, 2, 10))

I am new to python and am not very good with tuples o(2, 2, 10, 10, 344, 344, 45, 43, 2, 2, 10, 10, 12, 8, 2, 10)r lists. My friend said i should split it but i just cant get it -_-

I need to split the tuple into tuples with 4 elements that i will later use a rectangles to draw to a image with PIL.

+5  A: 

Well there is a certain idiom for that:

def grouper(n, iterable):
    args = [iter(iterable)] * n
    return zip(*args)

t = (2, 2, 10, 10, 344, 344, 45, 43, 2, 2, 10, 10, 12, 8, 2, 10)
print grouper(4, t)

But its kind of complicated to explain. A slightly more general version of this is listed in the itertools receipes.

You can also slice the tuple yourself

parts = (t[0:4], t[4:8], t[8:12], t[12:16])

# or as a function
def grouper2(n, lst):
    return [t[i:i+n] for i in range(0, len(t), n)]

which is probably what your friend meant.

THC4k
I wouldn't call that idiomatic--I've never even seen it before, and it took me several seconds to figure out what was going on. There's nothing wrong with this, but of course, be sure to document and doctest.
Glenn Maynard
Thanks it worked :D
giodamelio
By the way, I'd strongly recommend `return itertools.izip(*args)`, so this works properly with large iterators by not trying to consume the entire iterator. A good test input is `itertools.cycle((1,2,3))`.
Glenn Maynard
I've seen that on here before often enough to consider it an idiom in the "SO dialect" of Python.
intuited
@Glenn Maynard: I've seen and used tit a few times, because it's pretty much the only way to group items from a generators. So I guess that's why i think of it as a idiom and also because it's pretty neat ;-) Anyways, `izip` is always a good idea, but for now I'll leave it without the extra import, just for simplicity's sake.
THC4k
The problem is people inevitably copy and paste code as-is. I don't think it's a win to proliferate a less correct version because it's one less line of code.
Glenn Maynard
A: 

Use the split command:

myTuple[0:4]

to get the first four items in a tuple. This can also be done with a list to get a list.

Here's how you'd do it

tuple( myTuple[i*4:(i+1)*4] for i in range(0,4) )
wheaties
So it would be `newTuple = oldTuple[0:4], oldTuple[4:8], oldTuple[8:12], oldTuple[12:]`
rsenna
A: 

Another possible answer (using a generator):

 oldTuple = (2, 2, 10, 10, 344, 344, 45, 43, 2, 2, 10, 10, 12, 8, 2, 10)
 newTuple = tuple(oldTuple[x:x+4] for x in range(0, len(oldTuple), 4))
rsenna
A: 
>>> atup
(2, 2, 10, 10, 344, 344, 45, 43, 2, 2, 10, 10, 12, 8, 2, 10)
>>> [ atup[n:n+4] for n,i in enumerate(atup) if n%4==0 ]
[(2, 2, 10, 10), (344, 344, 45, 43), (2, 2, 10, 10), (12, 8, 2, 10)]
ghostdog74
A: 

I had written such a function as gist some time back, available at http://gist.github.com/616853

def split(input_list,num_fractions=None,subset_length=None):
   '''                                                                                                                                
   Given a list/tuple split original list based on either one of two parameters given but NOT both,                                   
   Returns generator                                                                                                                  
   num_fractions : Number of subsets original list has to be divided into, of same size to the extent possible.                       
                   In case equilength subsets can't be generated, all but the last subset                                             
                   will have the same number of elements.                                                                             
   subset_length : Split on every subset_length elements till the list is exhausted.                                                  

   '''
   if not input_list:
       yield input_list #For some reason I can't just return from here : return not allowed in generator expression                   
   elif not bool(num_fractions) ^ bool(subset_length): #Will check for both the invalid cases, '0' and 'None'.. Oh Python :)          
       raise Exception("Only one of the params : num_fractions,subset_length to be provided")
   else:
       if num_fractions: #calcluate subset_length in this case                                                                        
           subset_length = max(len(input_list)/num_fractions,1)

       for start in xrange(0,len(input_list),subset_length):
           yield input_list[start:start+subset_length]



>> list(list_split.split((2, 2, 10, 10, 344, 344, 45, 43, 2, 2, 10, 10, 12, 8, 2, 10),subset_length=4))
 [(2, 2, 10, 10), (344, 344, 45, 43), (2, 2, 10, 10), (12, 8, 2, 10)]

The code is longer than the solutions given above, but covers all possible sequence split conditions.

Ashish
Thanks but the one above works just fine. saving the code as it could be very use full in the right place.
giodamelio