Moving to functional programming

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

    Moving to functional programming

    Hi all,

    Had a simple problem that turned into an interesting solution and I
    thought I would share it here.

    I had a list of tuples that I needed to get the first value from and
    generate a list.

    tuple_list = (
    ('John', 'Doe'),
    ('Mark', 'Mason'),
    ('Jeff', 'Stevens'),
    ('Bat', 'Man')
    )

    # what I'd do in C or other procedural languages
    result_list = []
    for item in tuple_list:
    result_list.app end(item[0])

    # the first Pythonic attempt using comprehensions
    result_list = [x[0] for x in tuple_list]

    # the final functional way
    [result_list, _] = zip(*tuple_list )

    I really like how Python allows me to do what I feel is the most
    natural solution (for a seasoned procedural programmer) while allowing
    a satisfying path towards a more functional approach.

    Cheers,
    James
  • bearophileHUGS@lycos.com

    #2
    Re: Moving to functional programming

    James Fassett:
    # the first Pythonic attempt using comprehensions
    result_list = [x[0] for x in tuple_list]
    >
    # the final functional way
    [result_list, _] = zip(*tuple_list )
    >
    I really like how Python allows me to do what I feel is the most
    natural solution (for a seasoned procedural programmer) while allowing
    a satisfying path towards a more functional approach.
    The list comprehension is quite more readable to me, so I suggest you
    to use it. It's probably the default way to do it in Python.

    If you want functional code this is another way (I have not tested the
    relative performance but it may be quick):
    >>tuple_list = (
    .... ('John', 'Doe'),
    .... ('Mark', 'Mason'),
    .... ('Jeff', 'Stevens'),
    .... ('Bat', 'Man')
    .... )
    >>from operator import itemgetter
    >>map(itemgette r(0), tuple_list)
    ['John', 'Mark', 'Jeff', 'Bat']

    Bye,
    bearophile

    Comment

    • craig75

      #3
      Re: Moving to functional programming

      On Jul 11, 3:36 am, bearophileH...@ lycos.com wrote:
      James Fassett:
      >
      # the first Pythonic attempt using comprehensions
      result_list = [x[0] for x in tuple_list]
      >
      # the final functional way
      [result_list, _] = zip(*tuple_list )
      >
      I really like how Python allows me to do what I feel is the most
      natural solution (for a seasoned procedural programmer) while allowing
      a satisfying path towards a more functional approach.
      >
      The list comprehension is quite more readable to me, so I suggest you
      to use it. It's probably the default way to do it in Python.
      >
      If you want functional code this is another way (I have not tested the
      relative performance but it may be quick):
      >
      >tuple_list = (
      >
      ...     ('John', 'Doe'),
      ...     ('Mark', 'Mason'),
      ...     ('Jeff', 'Stevens'),
      ...     ('Bat', 'Man')
      ...   )>>from operator import itemgetter
      >map(itemgetter (0), tuple_list)
      >
      ['John', 'Mark', 'Jeff', 'Bat']
      >
      Bye,
      bearophile

      Functional programmers love pattern matching (which I think makes the
      code much easier to understand):

      [x for (x,y) in tuple_list]

      or

      map(lambda (x,y):x, tuple_list)

      Comment

      • sturlamolden

        #4
        Re: Moving to functional programming

        On Jul 11, 12:00 pm, James Fassett <ja...@reggieba nd.comwrote:
        tuple_list = (
            ('John', 'Doe'),
            ('Mark', 'Mason'),
            ('Jeff', 'Stevens'),
            ('Bat', 'Man')
          )
        >
        # what I'd do in C or other procedural languages
        result_list = []
        for item in tuple_list:
            result_list.app end(item[0])
        Here are some various 'functional' solutions. Pick the one that fits
        your problem best:

        result_list = [fn for fn,ln in tuple_list]

        result_generato r = (fn for fn,ln in tuple_list)

        result_list = map(lambda (fn,ln): fn, result_list)

        result_generato r = itertools.imap( lambda (fn,ln): fn, result_list)


        Comment

        • Terry Reedy

          #5
          Re: Moving to functional programming



          bearophileHUGS@ lycos.com wrote:
          James Fassett:
          ># the first Pythonic attempt using comprehensions
          >result_list = [x[0] for x in tuple_list]
          This has the virtue of working for tuples of any length and doing the
          minimal work required.
          ># the final functional way
          >[result_list, _] = zip(*tuple_list )
          This requires the tuples in tuple_list to be of length 2. It also
          produces a second list that is then tossed away.
          The list comprehension is quite more readable to me, so I suggest you
          to use it. It's probably the default way to do it in Python.
          It also has two virtues that the non-equivalent alternative lacks.
          If you want functional code this is another way (I have not tested the
          relative performance but it may be quick):
          >
          >>>tuple_list = (
          ... ('John', 'Doe'),
          ... ('Mark', 'Mason'),
          ... ('Jeff', 'Stevens'),
          ... ('Bat', 'Man')
          ... )
          >>>from operator import itemgetter
          >>>map(itemgett er(0), tuple_list)
          ['John', 'Mark', 'Jeff', 'Bat']
          This again makes just one list from tuples of any length.

          Some of the other alternatives in another post do minimal work but only
          work with pairs.

          tjr

          Comment

          • James Fassett

            #6
            Re: Moving to functional programming

            On Jul 12, 12:18 am, George Sakkis <george.sak...@ gmail.comwrote:
            It relies on positional arguments, tuple unpacking and
            the signature of zip(),
            It moreso relies on the fact that:
            >>t1 = (0,1,2,3)
            >>t2 = (7,6,5,4)
            >>[t1, t2] == zip(*zip(t1, t2))
            True

            This is mathematically true given the definition of zip. To me that is
            very functional. Basically, unpacking a pair list into zip is the
            canonical definition of unzipping the list (which is exactly my
            intention).
            Second, it is less readable,
            For a Python programmer - you are correct. For someone familiar with
            the use of zip (as described above) - I wonder. Since I am new to this
            I can't say for sure. If I posted the same code to a Haskell list or a
            ML list would their opinion be the same?
            robust and efficient than the list comprehension.
            I don't know the internals of how the Python interpreter treats list
            comprehensions and zip but it seems reasonable to assume an extra list
            is created for the zip approach.

            However, in the limited functional code I have seen this is actually a
            common practice. I would suppose in languages with lazy evaluation
            this isn't a problem - but in Python it would be.
            The list comprehension is still the most pythonic approach though.
            I agree that it is more Pythonic and preferable in this case.

            Cheers,
            James

            Comment

            • bruno.desthuilliers@gmail.com

              #7
              Re: Moving to functional programming

              On 14 juil, 11:51, James Fassett <ja...@reggieba nd.comwrote:
              On Jul 12, 12:18 am, George Sakkis <george.sak...@ gmail.comwrote:
              >
              It relies on positional arguments, tuple unpacking and
              the signature of zip(),
              >
              It moreso relies on the fact that:
              >
              >t1 = (0,1,2,3)
              >t2 = (7,6,5,4)
              >[t1, t2] == zip(*zip(t1, t2))
              >
              True
              >
              This is mathematically true given the definition of zip. To me that is
              very functional. Basically, unpacking a pair list into zip is the
              canonical definition of unzipping the list (which is exactly my
              intention).
              >
              Second, it is less readable,
              >
              For a Python programmer - you are correct. For someone familiar with
              the use of zip (as described above) - I wonder. Since I am new to this
              I can't say for sure. If I posted the same code to a Haskell list or a
              ML list would their opinion be the same?
              You might find interesting than Python's list comprehensions were
              stolen from Haskell then !-)
              robust and efficient than the list comprehension.
              >
              I don't know the internals of how the Python interpreter treats list
              comprehensions
              According to a post on the pypy team's blog, mostly as sugar candy for
              the procedural version (IOW: the generated byte-code will be roughly
              equivalent).
              and zip but it seems reasonable to assume an extra list
              is created for the zip approach.
              >
              However, in the limited functional code I have seen this is actually a
              common practice. I would suppose in languages with lazy evaluation
              this isn't a problem - but in Python it would be.
              Python has some kind of lazy evaluation too - look for yield,
              generator expressions, iterators, and the itertools package.

              Comment

              • Terry Reedy

                #8
                Re: Moving to functional programming



                James Fassett wrote:
                <zip...
                >robust and efficient than the list comprehension.
                >
                I don't know the internals of how the Python interpreter treats list
                comprehensions and zip but it seems reasonable to assume an extra list
                is created for the zip approach.
                Minor times differences between this and that way of writing things tend
                to be version and even system dependent. In 3.0, for instance, zip
                produces an iterator, not a list. So it will be faster. On the other
                hand, list comprehensions will be a bit slower to fix what many,
                including Guido, consider to be a slight design bug.

                Comment

                • Paul Rubin

                  #9
                  Re: Moving to functional programming

                  James Fassett <james@reggieba nd.comwrites:
                  tuple_list = (
                  ('John', 'Doe'),
                  ('Mark', 'Mason'),
                  ('Jeff', 'Stevens'),
                  ('Bat', 'Man')
                  )
                  # the final functional way
                  [result_list, _] = zip(*tuple_list )
                  That's really ugly IMO. I'd use:

                  result_list = list(x for (x,y) in tuple_list)

                  I don't like square-bracket listcomps because they leak the index
                  variables to the outside.

                  Comment

                  • Ben Finney

                    #10
                    Re: Moving to functional programming

                    Paul Rubin <http://phr.cx@NOSPAM.i nvalidwrites:
                    I don't like square-bracket listcomps because they leak the index
                    variables to the outside.
                    According to PEP 289 <URL:http://www.python.org/dev/peps/pep-0289>,
                    this is an acknowledged wart that will be fixed in Python 3.0.

                    --
                    \ “None can love freedom heartily, but good men; the rest love |
                    `\ not freedom, but license.” —John Milton |
                    _o__) |
                    Ben Finney

                    Comment

                    • Terry Reedy

                      #11
                      Re: Moving to functional programming



                      Ben Finney wrote:
                      Paul Rubin <http://phr.cx@NOSPAM.i nvalidwrites:
                      >
                      >I don't like square-bracket listcomps because they leak the index
                      >variables to the outside.
                      >
                      According to PEP 289 <URL:http://www.python.org/dev/peps/pep-0289>,
                      this is an acknowledged wart that will be fixed in Python 3.0.
                      Has been.
                      IDLE 3.0b1
                      >>a=[i for i in range(5)]
                      >>i
                      Traceback (most recent call last):
                      File "<pyshell#1 >", line 1, in <module>
                      i
                      NameError: name 'i' is not defined

                      Comment

                      Working...