Howto: extract a 'column' from a list of lists into a new list?
Greg Brunet
gregbrunet at NOSPAMsempersoft.com
Tue Jul 1 23:20:06 EDT 2003
"Bengt Richter" <bokr at oz.net> wrote in message
news:bdspmf$leq$0 at 216.39.172.122...
> Or you can take advantage of zip:
>
> >>> fields = [
> ... ('STOCKNO', 'C', 8, 0),
> ... ('DACC', 'C', 5, 0),
> ... ('DEALERACCE', 'C', 30, 0),
> ... ('D-ACCRTL', 'C', 9, 0),
> ... ('D-ACCCST', 'C', 9, 0)
> ... ]
> >>> zip(*fields)[0]
> ('STOCKNO', 'DACC', 'DEALERACCE', 'D-ACCRTL', 'D-ACCCST')
>
> Or a list of all the columns of which only the first was selected
above:
> >>> zip(*fields)
> [('STOCKNO', 'DACC', 'DEALERACCE', 'D-ACCRTL', 'D-ACCCST'), ('C',
'C', 'C', 'C', 'C'), (8, 5, 30
> , 9, 9), (0, 0, 0, 0, 0)]
>
> Since zip gives you a list of tuples, you'll have to convert if you
really need a list version
> of one of them:
>
> >>> list(zip(*fields)[0])
> ['STOCKNO', 'DACC', 'DEALERACCE', 'D-ACCRTL', 'D-ACCCST']
Bengt:
This looks great - but something isn't quite working for me. If I type
in the stuff as you show, the zip function works, but if I use the
values that I get from my code, it doesn't. Here's what I get in a
sample session:
#------------------------------------
>>> ff=dbf('nd.dbf')
>>> ff.Fields()
[('STOCKNO', 'C', 8, 0), ('DACC', 'C', 5, 0), ('DEALERACCE', 'C', 30,
0), ('D_ACCRTL', 'C', 9, 0), ('D_ACCCST', 'C', 9, 0), ('DEC', 'N', 10,
2)]
>>> zip(*ff.Fields())
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
TypeError: zip argument #1 must support iteration
#------------------------------------
Where the "dbf" invoices the _init_ for the dbf class which opens the
file & reads the header. As part of that, the fields are placed in a
class variable, and accessed using the Fields() method. At first I
wasn't sure of what the '*' did, but finally figured that out (section
5.3.4-Calls of the Language Reference for anyone else who's confused).
After puzzling it through a bit, I believe that Fields() is causing the
problem because it's not really a list of tuples as it appears. Rather
it's a list of dbfField objects which have (among others) the following
2 methods:
class dbfField:
#----------------------------------------
def __init__(self):
pass
#----------------------------------------
def create (self, fldName, fldType='C', fldLength=10, fldDec=0):
# (lot's of error-checking omitted)
self._fld = (fldName, fldType, fldLength, fldDec)
#----------------------------------------
def __repr__(self):
return repr(self._fld)
#----------------------------------------
def __getitem__(self,key):
""" Return by position or item name """
if type(key) is IntType:
return self._fld[key]
elif type(key) is StringType:
ukey = key.upper()
if ukey=="NAME": return self._fld[0]
elif ukey=="TYPE": return self._fld[1]
elif ukey=="LENGTH": return self._fld[2]
elif ukey=="DEC": return self._fld[3]
What I was trying to do, was to use the _fld tuple as the main object,
but wrap it with various methods & properties to 'safeguard' it. Given
that can I still use zip to do what I want? (Egor & Max's list
comprehension solution works fine for me, but the zip function seems
especially elegant) I read in the library reference about iterator
types (sec 2.2.5 from release 2.2.2), and it looks like I could get it
to work by implementing the iterator protocol, but I couldn't find any
sample code to help in this. Any idea if there's some available, or if
this is even worth it.
Better yet, is there a way for me to accomplish the same thing in a
simpler way? It's likely that I'm 'brute-forcing' a solution that has
gotten to be a lot more complex than it needs to be. Certainly if the
field definitions were in a simple tuple (which it is internally), zip
would work, but then it seems that I would lose the encapsulation
benefits. Is there a way to achieve both?
Thanks again,
--
Greg
More information about the Python-list
mailing list