unpaking sequences of unknown length

A

Anthra Norell

Hi,

I keep working around a little problem with unpacking in cases in which I don't know how many elements I get. Consider this:

def tabulate_lists (*arbitray_number_of_lists):
table = zip (arbitray_number_of_lists)
for record in table:
# etc ...

This does not work, because the zip function also has an *arg parameter, which expects an arbitrary length enumeration of arguments
which it would turn into a tuple (lists in this case). Now my function does exactly the same thing ahead of zip. So, before I pass
the tuple "arbitrary_number_of_lists" to zip, I 'd need to unpack it but the only way I know of is into variables:

list1, list2, list3 = arbitrary_number_of_lists
zip (list1, list2, list3)

With arbitrary number of lists it cannot be done this way.

Question: Is there an unpacking mechanism for cases in which I don't know--and don't need to know--how many elements I get, or an
argument passing mechanism that is the inverse of the tuplifier (*args)?

table = zip (&arbitrary_number_of_lists) # I invent '&' to illustrate

I preclude passing a pre-zipped table as a solution, because all function-related argument processing should be done by the
function, not by the caller. Supposing my tabulator should auto-format a printout. It would need to analyze each column (e.g.
maxima, minima, max length of strings, etc.) That would be a lot simpler with column lists than with record lists, unless I undo
what the caller had to do, because the function couldn't ... a lot of in and out ...

Of course I could code a code edit and exec () it.

names_of_lists = ','.join (['list%d' % n for n in range (len (arbitrary_number_of_lists)])
exec ('"%s = arbitrary_number_of_lists"'% names_of_lists)
exec ('"table = zip (%s)"' % names_of_lists)

That should work, but it looks loathsome to me.


Has anyone come across a similar problem and found an elegant solution he might want to share?

Frederic
 
D

Diez B. Roggisch

I keep working around a little problem with unpacking in cases in which I don't know how many elements I get. Consider this:
def tabulate_lists (*arbitray_number_of_lists):
table = zip (arbitray_number_of_lists)
for record in table:
# etc ...

This does not work, because the zip function also has an *arg parameter, which expects an arbitrary length enumeration of arguments
which it would turn into a tuple (lists in this case). Now my function does exactly the same thing ahead of zip. So, before I pass
the tuple "arbitrary_number_of_lists" to zip, I 'd need to unpack it but the only way I know of is into variables:

list1, list2, list3 = arbitrary_number_of_lists
zip (list1, list2, list3)


I don't get your problem here. This works for me:

args = [range(5) for i in xrange(5)]

print zip(*args)
With arbitrary number of lists it cannot be done this way.

Question: Is there an unpacking mechanism for cases in which I don't know--and don't need to know--how many elements I get, or an
argument passing mechanism that is the inverse of the tuplifier (*args)?

No.

It looks a little bit as if you aren't aware of the symetry behind the *
and **-argument-passing schemes. I suggest reading up on them.

Diez
 
D

Diez B. Roggisch

Question: Is there an unpacking mechanism for cases in which I don't
No.

It looks a little bit as if you aren't aware of the symetry behind the *
and **-argument-passing schemes. I suggest reading up on them.

Sorry - I was somewhat unconcentrated and missed the last part of the
sentence. So it is

No "generalized", yes, the inverse of *args is foo(*args)

Sorry for the confusion.

Diez
 
G

Gerard Flanagan

Anthra said:
Hi,

I keep working around a little problem with unpacking in cases in which I don't know how many elements I get. Consider this:

def tabulate_lists (*arbitray_number_of_lists):
table = zip (arbitray_number_of_lists)
for record in table:
# etc ...

This does not work, because the zip function also has an *arg parameter, which expects an arbitrary length enumeration of arguments

maybe I don't understand the problem properly, but you can use '*args'
as 'args' or as '*args', if you see what I mean!, ie.

def tabulate_lists (*arbitray_number_of_lists):
table = zip (*arbitray_number_of_lists)
for record in table:
# etc ...

for example:

def sum_columns(*rows):
for col in zip(*rows):
yield sum(col)

for i, s in enumerate( sum_columns( [1,2], [3,2], [5,1] ) ):
print 'Column %s: SUM=%s' % (i,s)

Column 0: SUM=9
Column 1: SUM=5

-----------------------------------------------------

alternatively:

import itertools as it

def sum_columns2( iterable ):
for col in it.izip( *iterable ):
yield sum(col)

def iter_rows():
yield [1,2]
yield [3,2]
yield [5,1]

print list( sum_columns2( iter_rows() ) )

#(izip isn't necessary here, zip would do.)
 
A

Anthra Norell

I get it!
print a
print zip (a) # My mistake
print zip (*a) # Gerard's solution.
([1, 2, 3], [4, 5, 6], [7, 5, 34]) # Argument: tuple of lists
[([1, 2, 3],), ([4, 5, 6],), ([7, 5, 34],)] # My mistake
[(1, 4, 7), (2, 5, 5), (3, 6, 34)] # That's what I want

Thank you all

Frederic


----- Original Message -----
From: "Gerard Flanagan" <[email protected]>
Newsgroups: comp.lang.python
To: <[email protected]>
Sent: Sunday, August 27, 2006 2:59 PM
Subject: Re: unpaking sequences of unknown length

Anthra said:
Hi,

I keep working around a little problem with unpacking in cases in which I don't know how many elements I get. Consider this:

def tabulate_lists (*arbitray_number_of_lists):
table = zip (arbitray_number_of_lists)
for record in table:
# etc ...

This does not work, because the zip function also has an *arg parameter, which expects an arbitrary length enumeration of
arguments

maybe I don't understand the problem properly, but you can use '*args'
as 'args' or as '*args', if you see what I mean!, ie.

def tabulate_lists (*arbitray_number_of_lists):
table = zip (*arbitray_number_of_lists)
for record in table:
# etc ...

for example:

def sum_columns(*rows):
for col in zip(*rows):
yield sum(col)

for i, s in enumerate( sum_columns( [1,2], [3,2], [5,1] ) ):
print 'Column %s: SUM=%s' % (i,s)

Column 0: SUM=9
Column 1: SUM=5

-----------------------------------------------------

alternatively:

import itertools as it

def sum_columns2( iterable ):
for col in it.izip( *iterable ):
yield sum(col)

def iter_rows():
yield [1,2]
yield [3,2]
yield [5,1]

print list( sum_columns2( iter_rows() ) )

#(izip isn't necessary here, zip would do.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top