map, filter & reduce...

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Ben

    map, filter & reduce...

    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/developerwork...ry/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
  • John Roth

    #2
    Re: map, filter & reduce...


    "Ben" <crescent_au@ya hoo.com> wrote in message
    news:d99e1341.0 311160416.20f8c f18@posting.goo gle.com...[color=blue]
    > 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/developerwork...ry/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??[/color]

    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[color=blue]
    >
    > Thanks
    > Ben[/color]


    Comment

    • Peter Otten

      #3
      Re: map, filter &amp; reduce...

      Ben wrote:
      [color=blue]
      > 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/developerwork...ry/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[/color]

      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.
      [color=blue][color=green][color=darkred]
      >>> map(None, range(3), range(2))[/color][/color][/color]
      [(0, 0), (1, 1), (2, None)][color=blue][color=green][color=darkred]
      >>>[/color][/color][/color]

      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:
      [color=blue][color=green][color=darkred]
      >>> dupelms(range(3 ), 2)[/color][/color][/color]
      [0, 0, 1, 1, 2, 2][color=blue][color=green][color=darkred]
      >>>[/color][/color][/color]

      This is then zipped (though by map())
      with a list similar to[color=blue][color=green][color=darkred]
      >>> range(2)*3[/color][/color][/color]
      [0, 1, 0, 1, 0, 1]
      [color=blue][color=green][color=darkred]
      >>> map(None, [0,0,1,1,2,2], [0,1,0,1,0,1])[/color][/color][/color]
      [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)][color=blue][color=green][color=darkred]
      >>>[/color][/color][/color]

      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

      Comment

      • Jan-Erik Meyer-Lütgens

        #4
        strange behaviour of sum()

        Ben wrote:[color=blue]
        > 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/developerwork...ry/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) )
        >[/color]

        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(la mbda (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*le n(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(l ambda 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(sequenc e). 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(String Type):
        # __metaclass__ = type

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

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

        def __add__(self, other):
        return MyString(str(se lf) + ' ' + 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?

        Comment

        • Inyeol Lee

          #5
          Re: strange behaviour of sum()

          On Wed, Nov 19, 2003 at 11:46:07PM +0100, Jan-Erik Meyer-Lütgens wrote:
          [...][color=blue]
          > I'd ran into trouble when I've used sum() naively:[/color]
          [...][color=blue]
          > 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:[/color]

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



          and Guido's summary at



          ..

          -Inyeol Lee

          Comment

          Working...