Splitting a long tuple into smaller tuples
Asked Answered
S

5

12

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.

Sclerophyll answered 16/10, 2010 at 1:56 Comment(2)
It would be good if you explained what you're doing with the tuple that requires it to be split. You'll probably get more useful and informative answers that way.Panorama
@JohnD: FWIW, I don't think this is complex or unusual enough that it needs a lot of context.Montserrat
L
10

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.

Lettering answered 16/10, 2010 at 2:3 Comment(5)
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.Montserrat
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)).Montserrat
I've seen that on here before often enough to consider it an idiom in the "SO dialect" of Python.Resinoid
@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.Lettering
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.Montserrat
U
4
>>> 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)]
Uncalledfor answered 16/10, 2010 at 2:19 Comment(1)
Like @Uncalledfor answers because, even if last tuple has 1 element in it, it becomes last tuple with 1 element, other solutions simply leaves last tuple of 1 element out.Zola
V
0

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))
Viand answered 16/10, 2010 at 2:19 Comment(0)
Z
0

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.

Zachar answered 16/10, 2010 at 5:20 Comment(1)
Thanks but the one above works just fine. saving the code as it could be very use full in the right place.Sclerophyll
R
0

You can do this using the dollop package (pip install dollop):

from dollop import serve

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

for serving in serve(tup, N=4):
    print(serving)

Output:

(2, 2, 10, 10)
(344, 344, 45, 43)
(2, 2, 10, 10)
(12, 8, 2, 10)
Recrudescence answered 24/8 at 12:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.