Making things more functional in Python

Discussion in 'Python' started by gf gf, Mar 4, 2005.

  1. gf gf

    gf gf Guest

    Is there a better, more FP style, more Pythonic way to
    write this:

    def compute_vectors(samples, dset):
    vectors = {}
    for d in dset:
    vectors[d] = [sample.get_val(d) for sample in
    samples]
    return vectors

    Namely, I'd like to get rid of the initilization
    (vectors = {}) and also the loop Yet, I'd hate to put
    an assignment into Python's FP list comprehensions.

    Ideally, I'd like something like this:
    vectors.dict_add({d:result}) for [sample.get_val(d)
    for sample in samples for d in dset].

    Is there anything like that? Am I missing the
    picture?

    Thanks.

    PS If possible, please cc me on all responses, thanks.




    __________________________________
    Celebrate Yahoo!'s 10th Birthday!
    Yahoo! Netrospective: 100 Moments of the Web
    http://birthday.yahoo.com/netrospective/
     
    gf gf, Mar 4, 2005
    #1
    1. Advertising

  2. gf gf wrote:
    > Is there a better, more FP style, more Pythonic way to
    > write this:
    >
    > def compute_vectors(samples, dset):
    > vectors = {}
    > for d in dset:
    > vectors[d] = [sample.get_val(d) for sample in
    > samples]
    > return vectors
    >
    > Namely, I'd like to get rid of the initilization
    > (vectors = {}) and also the loop


    Generate the whole dictionary on the fly with a Python 2.4 generator
    expression:

    dict((d, [sample.get_val(d) for sample in samples]) for d in dset)

    Whether this is "better" or not I think mainly hinges on which
    one you ahve an easier time understanding later. Personally I would
    prefer this version, but it's easy to get carried away trying to
    functionalize things to the point that a procedural version is much
    easier to understand.

    > Yet, I'd hate to put an assignment into Python's FP list
    > comprehensions.


    Indeed it's not possible to have an assignment in a list comprehension.
    (Unless it's a side-effect due to a function called by the list
    comprehension.)

    > Ideally, I'd like something like this:
    > vectors.dict_add({d:result}) for [sample.get_val(d)
    > for sample in samples for d in dset].


    You can't use the name "vectors" without first initializing it
    somehow!
    --
    Michael Hoffman
     
    Michael Hoffman, Mar 4, 2005
    #2
    1. Advertising

  3. gf gf

    Steve Holden Guest

    gf gf wrote:
    > Is there a better, more FP style, more Pythonic way to
    > write this:
    >
    > def compute_vectors(samples, dset):
    > vectors = {}
    > for d in dset:
    > vectors[d] = [sample.get_val(d) for sample in
    > samples]
    > return vectors
    >
    > Namely, I'd like to get rid of the initilization
    > (vectors = {}) and also the loop Yet, I'd hate to put
    > an assignment into Python's FP list comprehensions.
    >
    > Ideally, I'd like something like this:
    > vectors.dict_add({d:result}) for [sample.get_val(d)
    > for sample in samples for d in dset].
    >
    > Is there anything like that? Am I missing the
    > picture?
    >
    > Thanks.
    >
    > PS If possible, please cc me on all responses, thanks.
    >

    The logical thing to use would be

    return dict([(d, sample.getval(d)) for d in dset for sample in samples])

    which (I think) should work from 2.2 onwards.

    regards
    Steve
    --
    Meet the Python developers and your c.l.py favorites March 23-25
    Come to PyCon DC 2005 http://www.pycon.org/
    Steve Holden http://www.holdenweb.com/
     
    Steve Holden, Mar 4, 2005
    #3
  4. Steve Holden wrote:

    > return dict([(d, sample.getval(d)) for d in dset for sample in samples])


    That won't do what the original code does. This sets dict[d] to
    samples[-1].getval(d) instead of [sample.getval(d) for sample in samples].
    --
    Michael Hoffman
     
    Michael Hoffman, Mar 4, 2005
    #4
  5. gf gf

    Steve Holden Guest

    Michael Hoffman wrote:
    > Steve Holden wrote:
    >
    >> return dict([(d, sample.getval(d)) for d in dset for sample in samples])

    >
    >
    > That won't do what the original code does. This sets dict[d] to
    > samples[-1].getval(d) instead of [sample.getval(d) for sample in samples].


    My bad, I didn;t look closely enbough to see the need for the nested
    comprehensions.

    regards
    Steve
    --
    Meet the Python developers and your c.l.py favorites March 23-25
    Come to PyCon DC 2005 http://www.pycon.org/
    Steve Holden http://www.holdenweb.com/
     
    Steve Holden, Mar 4, 2005
    #5
  6. On Fri, 2005-03-04 at 08:36 -0800, gf gf wrote:
    > Is there a better, more FP style, more Pythonic way to
    > write this:
    >
    > def compute_vectors(samples, dset):
    > vectors = {}
    > for d in dset:
    > vectors[d] = [sample.get_val(d) for sample in
    > samples]
    > return vectors


    You could use reduce:

    def compute_vectors(samples, dset):
    def add_entry(vectors, d):
    vectors[d] = [sample.get_val(d) for sample in samples]
    return vectors
    return reduce(add_entry, dset, {})

    Dave
     
    Dave Benjamin, Mar 5, 2005
    #6
  7. On Sat, 2005-03-05 at 00:00 -0700, Dave Benjamin wrote:
    > On Fri, 2005-03-04 at 08:36 -0800, gf gf wrote:
    > > Is there a better, more FP style, more Pythonic way to
    > > write this:
    > >
    > > def compute_vectors(samples, dset):
    > > vectors = {}
    > > for d in dset:
    > > vectors[d] = [sample.get_val(d) for sample in
    > > samples]
    > > return vectors

    >
    > You could use reduce:
    >
    > def compute_vectors(samples, dset):
    > def add_entry(vectors, d):
    > vectors[d] = [sample.get_val(d) for sample in samples]
    > return vectors
    > return reduce(add_entry, dset, {})


    This could be further generalized:

    def compute(xs, ys, f):
    def add_entry(result, y):
    result[y] = [f(x, y) for x in xs]
    return result
    return reduce(add_entry, ys, {})

    Now, compute_vectors is just:

    compute(samples, dset, lambda x, y: x.get_val(y))

    You could even abstract the method call:

    def method(name):
    def _method(obj, *args, **kwds):
    return getattr(obj, name)(*args, **kwds)
    return _method

    compute(samples, dset, method('get_val'))

    Dave
     
    Dave Benjamin, Mar 5, 2005
    #7
    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. Replies:
    15
    Views:
    272
    Ramchandra Apte
    Sep 23, 2012
  2. Chris Angelico
    Replies:
    0
    Views:
    206
    Chris Angelico
    Sep 21, 2012
  3. Chris Rebert
    Replies:
    0
    Views:
    172
    Chris Rebert
    Sep 21, 2012
  4. Chris Angelico
    Replies:
    0
    Views:
    180
    Chris Angelico
    Sep 21, 2012
  5. Chris Rebert
    Replies:
    0
    Views:
    210
    Chris Rebert
    Sep 21, 2012
Loading...

Share This Page