map, filter & reduce...

B

Ben

Hi all,

I'm trying to figure out how how complex map, filter and reduce work
based on the following piece of code from
http://www-106.ibm.com/developerworks/linux/library/l-prog.html :

bigmuls = lambda xs,ys: filter(lambda (x,y):x*y > 25, combine(xs,ys))
combine = lambda xs,ys: map(None, xs*len(ys), dupelms(ys,len(xs)))
dupelms = lambda lst,n: reduce(lambda s,t:s+t, map(lambda l,n=n:
[l]*n, lst))
print bigmuls((1,2,3,4),(10,15,3,22))

The solution generated by the above code is: [(3, 10), (4, 10), (2,
15), (3, 15), (4, 15), (2, 22), (3, 22), (4, 22)]

I'm stuck on the second line in "map(None, xs*len(ys),
dupelms(ys,len(xs))"... Can someone explain me how the map function
evaluates??

Thanks
Ben
 
J

John Roth

Ben said:
Hi all,

I'm trying to figure out how how complex map, filter and reduce work
based on the following piece of code from
http://www-106.ibm.com/developerworks/linux/library/l-prog.html :

bigmuls = lambda xs,ys: filter(lambda (x,y):x*y > 25, combine(xs,ys))
combine = lambda xs,ys: map(None, xs*len(ys), dupelms(ys,len(xs)))
dupelms = lambda lst,n: reduce(lambda s,t:s+t, map(lambda l,n=n:
[l]*n, lst))
print bigmuls((1,2,3,4),(10,15,3,22))

The solution generated by the above code is: [(3, 10), (4, 10), (2,
15), (3, 15), (4, 15), (2, 22), (3, 22), (4, 22)]

I'm stuck on the second line in "map(None, xs*len(ys),
dupelms(ys,len(xs))"... Can someone explain me how the map function
evaluates??

In this case, map is (almost) a synonym for zip. It's going to
create a list where each entry is a two item list containing the
corresponding elements from each of the inputs. The first
input is, of course, the result of the multiply, and the second
is whatever the dupelms() call produced.

John Roth
 
P

Peter Otten

Ben said:
Hi all,

I'm trying to figure out how how complex map, filter and reduce work
based on the following piece of code from
http://www-106.ibm.com/developerworks/linux/library/l-prog.html :

bigmuls = lambda xs,ys: filter(lambda (x,y):x*y > 25, combine(xs,ys))
combine = lambda xs,ys: map(None, xs*len(ys), dupelms(ys,len(xs)))
dupelms = lambda lst,n: reduce(lambda s,t:s+t, map(lambda l,n=n:
[l]*n, lst))
print bigmuls((1,2,3,4),(10,15,3,22))

The solution generated by the above code is: [(3, 10), (4, 10), (2,
15), (3, 15), (4, 15), (2, 22), (3, 22), (4, 22)]

I'm stuck on the second line in "map(None, xs*len(ys),
dupelms(ys,len(xs))"... Can someone explain me how the map function
evaluates??

Thanks
Ben

Do yourself a favour and read on to the sane version that uses a list
comprehension :) By the way, David Mertz has deliberately obfuscated the
traditional imperative approach by not preserving the block structure and
inserting superfluous comments.

map(None, seq1, seq2) returns a list of tuples (seq1[0], seq2[0]) etc. The
sequence item is substituted with None, if a sequence is exhausted, e. g.
map(None, range(3), range(2)) [(0, 0), (1, 1), (2, None)]

but that doesn't occur here, making zip() instead of map() a better choice.

Putting it all together:
dupelms() takes a list and a length n creating a new list where each item of
the original list is duplicated n times:
dupelms(range(3), 2) [0, 0, 1, 1, 2, 2]

This is then zipped (though by map())
with a list similar to [0, 1, 0, 1, 0, 1]
map(None, [0,0,1,1,2,2], [0,1,0,1,0,1]) [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]

This last list is then filtered for items (the tuples), that meet the
condition
item[0]*item[1] > 25

To imagine how errorprone this code is and to check how well it scales with
large lists is left as an exercise to the reader...

Peter
 
?

=?ISO-8859-1?Q?Jan-Erik_Meyer-L=FCtgens?=

Ben said:
I'm trying to figure out how how complex map, filter and reduce work
based on the following piece of code from
http://www-106.ibm.com/developerworks/linux/library/l-prog.html :

bigmuls = lambda xs,ys: filter(lambda (x,y):x*y > 25, combine(xs,ys))
combine = lambda xs,ys: map(None, xs*len(ys), dupelms(ys,len(xs)))
dupelms = lambda lst,n: reduce(lambda s,t:s+t, map(lambda l,n=n:
[l]*n, lst))
print bigmuls((1,2,3,4),(10,15,3,22))

Hi all,

I've played with this example, also. I'd rewritten the example
using zip() and sum(), when I've noticed a quirk of the sum() function.

# keep pairs whose product is greater than 25.
bigmuls=lambda xs,ys:filter(lambda (x,y): x*y>25, combine(xs, ys))

# compute the cross product of two lists.
# combine([1,2],[3,4]) --> [(1, 3), (2, 3), (1, 4), (2, 4)]
combine=lambda xs,ys:zip(xs*len(ys), dupelms(ys, len(xs)))

# duplicate elements of lst n times.
# dupelms([1,2], 3) --> [1, 1, 1, 2, 2, 2]
dupelms=lambda lst,n:sum(map(lambda element,n=n:[element]*n, lst),[])


I'd ran into trouble when I've used sum() naively:

sum([ [1], [2], [3] ])

results in:

TypeError: unsupported operand type(s) for +: 'int' and 'list'


A peek in the language reference:

sum(sequence[, start])
Sums start and the items of a sequence, from left to right,
and returns the total. start defaults to 0. The sequence's
items are normally numbers, and are not allowed to be strings.
The fast, correct way to concatenate sequence of strings
is by calling ''.join(sequence). Note that sum(range(n), m)
is equivalent to reduce(operator.add, range(n), m)
New in version 2.3.


As we can see:
sum(seq, start) is equivalent to reduce(operator.add, seq, start)

but:
sum(seq) is not equivalent to reduce(operator.add, seq)

because: start of sum() defaults to 0. So we must set the
start value explicit to the neutral element for the addition:

sum([ [1], [2], [3] ], [])


The other strange behaviour is:

sum(['my', 'pet', 'fish', 'eric'], '')

results in:

TypeError: sum() can't sum strings [use ''.join(seq) instead]

If there is a special treatment for strings, why doesn't sum()
use ''.join(seq) itself, instead of telling me that I should
use it? But in fact sum() should call operator.add(), even
for strings:


from types import StringType

class MyString(StringType):
# __metaclass__ = type

def __init__(self, value):
StringType.__init__(self, value)

def __str__(self):
return StringType.__str__(self)

def __add__(self, other):
return MyString(str(self) + ' ' + str(other))

my = MyString('my')
pet = MyString('pet')
fish = MyString('fish')
eric = MyString('eric')

# different output (with intent):
print my + pet + fish + eric # --> my pet fish erik
print ''.join([my, pet, fish, eric]) # --> mypetfisheric

# two quirks for sum(), here:
# 1. does not work, because MyString is a subclass of string
# 2. result have an extra unwanted space (if it would work)
print sum( [my, pet, fish, eric], MyString('') )


I would treat this quirks as unpythonic, cause the behaviour
of the sum() function is not generic and not intuitive.

Will this be fixed in future releases of python?
 
I

Inyeol Lee

]
I'd ran into trouble when I've used sum() naively: [...]
The other strange behaviour is:

sum(['my', 'pet', 'fish', 'eric'], '')

results in:

TypeError: sum() can't sum strings [use ''.join(seq) instead]

If there is a special treatment for strings, why doesn't sum()
use ''.join(seq) itself, instead of telling me that I should
use it? But in fact sum() should call operator.add(), even
for strings:

There was a duscussion on this in python-dev. See thread starting from

http://mail.python.org/pipermail/python-dev/2003-April/034767.html

and Guido's summary at

http://mail.python.org/pipermail/python-dev/2003-April/034853.html

..

-Inyeol Lee
 

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,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top