a small problem

Thomas Wouters thomas at xs4all.net
Tue Jan 11 19:59:24 EST 2000


On Wed, Jan 12, 2000 at 12:06:50AM +0000, knotwell at my-deja.com wrote:

> Is the following a bug?

> >>> q = [(1,'dd'),(2,'ddd'),(3,'ddddd')]

> >>> reduce(lambda x,y: x[0] + y[0],q)

> Traceback (innermost last):
>   File "<stdin>", line 1, in ?
>   File "<stdin>", line 1, in <lambda>
> AttributeError: __getitem__

My version of Python (admittedly, the CVS version) says something slightly
more obvious:

>>> q = [(1,'dd'),(2,'ddd'),(3,'ddddd')]
>>> reduce(lambda x,y: x[0] + y[0],q)
Traceback (innermost last):
  File "<stdin>", line 1, in ?
  File "<stdin>", line 1, in <lambda>
TypeError: unsubscriptable object

The problem is not in map, but in your lambda. You have to remember what
reduce does :)

For the first run, if not given an 'initial' value, it takes the first two
elements of the list, and gives them to the passed function (the lambda, in
your case.) If you give an initial value, it uses that and the first element
of the list, and passes that to the function.

For every subsequent run, it runs the function on the return value of the
_previous_ run, and the next element of the list.

So, in your example, here's what happens:

reduce takes (1,'dd') and (2,'ddd'), and passes them to the lambda
The lambda takes 1 ((1,'dd')[0]) and 2 ((2,'ddd')[0]) and adds them,
yielding 3.

reduce takes 3 and (3,'ddddd') and passes them to lambda
lambda tries to do '3[0]', and fails.

You need to do something like this, to force lambda to return an indexable
object (of which element 0 is the element you want reduce to use next time.)

>>> reduce(lambda x,y: (x[0] + y[0],),q)
(6,)

or perhaps

>>> reduce(lambda x,y: (x[0] + y[0],),q)[0]
6

depending on what you want. But I think this is roughly the point where
people like Guido(*) start wondering if reduce is a good idea at all. I'd
say the above reduce is almost a good argument for perl ;) Usually, what
you're trying to do so forcefully with just reduce and lambda is much more
elegantly (and readably!) done with map and reduce (and lambda, in this
case):

>>> import operator
>>> tmplist = map(lambda x: x[0], q)
>>> tmplist
[1, 2, 3]
>>> reduce(operator.add, tmplist)
6

(This may seem like nitpicking for the above example, but it makes for
readable code later on, when you write longer and longer and more
complicated map/filter/reduce sequences. The FAQ has a nice example, in the
'oneliner' section ;)

(*) I'm assuming here. I dont actually know so, because i'm not foolish
enough to consider myself knowledgable in all things Guido, but these are
the hints i get from other postings on the subject, by other people.

bytesize-chunks-of-code-make-a-pleasant-meal-ly y'rs,
-- 
Thomas Wouters <thomas at xs4all.net>

Hi! I'm a .signature virus! copy me into your .signature file to help me spread!




More information about the Python-list mailing list