Moving to functional programming

Discussion in 'Python' started by James Fassett, Jul 11, 2008.

  1. 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.append(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
    James Fassett, Jul 11, 2008
    #1
    1. Advertising

  2. James Fassett

    Guest

    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
    , Jul 11, 2008
    #2
    1. Advertising

  3. James Fassett

    craig75 Guest

    On Jul 11, 3:36 am, 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)
    craig75, Jul 11, 2008
    #3
  4. James Fassett

    sturlamolden Guest

    On Jul 11, 12:00 pm, James Fassett <> wrote:

    > 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.append(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_generator = (fn for fn,ln in tuple_list)

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

    result_generator = itertools.imap(lambda (fn,ln): fn, result_list)
    sturlamolden, Jul 11, 2008
    #4
  5. James Fassett

    Terry Reedy Guest

    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(itemgetter(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
    Terry Reedy, Jul 11, 2008
    #5
  6. On Jul 11, 1:00 pm, James Fassett <> wrote:
    > 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.append(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.


    First off, what exactly does make you think of the last approach as
    "functional" ? It relies on positional arguments, tuple unpacking and
    the signature of zip(), none of which are functional in the usual
    programming language sense of the word. Second, it is less readable,
    robust and efficient than the list comprehension.

    An example of a really functional approach without all these drawbacks
    would be bearophile's map(itemgetter(0), tuple_list) since
    itemgetter() is a high order function (more specifically, a function
    that returns another function). The list comprehension is still the
    most pythonic approach though.

    Regards,
    George
    George Sakkis, Jul 12, 2008
    #6
  7. On Jul 12, 12:18 am, George Sakkis <> wrote:
    > 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
    James Fassett, Jul 14, 2008
    #7
  8. James Fassett

    Guest

    On 14 juil, 11:51, James Fassett <> wrote:
    > On Jul 12, 12:18 am, George Sakkis <> wrote:
    >
    > > 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.
    , Jul 14, 2008
    #8
  9. James Fassett

    Terry Reedy Guest

    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.
    Terry Reedy, Jul 14, 2008
    #9
  10. James Fassett

    Paul Rubin Guest

    James Fassett <> writes:
    > 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.
    Paul Rubin, Jul 16, 2008
    #10
  11. James Fassett

    Terry Reedy Guest

    Ben Finney wrote:
    > Paul Rubin <http://> writes:
    >
    >> 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
    Terry Reedy, Jul 16, 2008
    #11
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Casey Hawthorne
    Replies:
    4
    Views:
    987
    Jarek Zgoda
    Aug 4, 2006
  2. Joe Mayo
    Replies:
    168
    Views:
    3,249
    David Thompson
    Oct 22, 2007
  3. linkswanted
    Replies:
    0
    Views:
    737
    linkswanted
    Dec 21, 2007
  4. linkswanted
    Replies:
    0
    Views:
    1,545
    linkswanted
    Jan 6, 2008
  5. Ben Burdick
    Replies:
    1
    Views:
    83
    Ara.T.Howard
    Sep 20, 2005
Loading...

Share This Page