1

I just wrote this function:

def _apply(mols, fn, *args, **kwargs):
    return [fn(m, *args, **kwargs) for m in mols if m ]

And I started thinking:

  1. Can this be rewritten using map?
  2. Is this already implemented in somewhere in python?

As far as I know, map can't pass arguments to the function, on the other hand, it may be somehow optimized and using some partial binding or lambdas I can reimplement it using map. Would that be beneficial?

martineau
  • 119,623
  • 25
  • 170
  • 301
mnowotka
  • 16,430
  • 18
  • 88
  • 134

2 Answers2

6

Yes, you can

from functools import partial

clean = partial(filter, None)

def _apply(mols, fn, *args, **kwargs):
    f = partial(fn, *args, **kwargs)
    return map(f, clean(mols))

def foo(m, a, b, c=123):
    return [m, a, b, c]

print _apply([11,22,'',33], foo, 'aa', 'bb', c=475)

(in python2, consider itertools.imap/ifilter instead of map/filter to avoid temporary lists).

The above illustrates "partial application", even more elegant would be currying, i.e. a function that returns a partially applied version of itself when called with less arguments than expected. Python doesn't have currying built-in, but it's easy to implement as a decorator (see https://stackoverflow.com/a/9458386/989121):

@curry
def join_three(a,b,c):
    return '%s-%s-%s' % (a,b,c)

mols = [11,22,33]
print map(join_three('aa', 'bb'), mols)
# prints ['aa-bb-11', 'aa-bb-22', 'aa-bb-33']

That said, functional style is frowned upon in python, in most cases, comprehensions and generators are more "pythonic".

Community
  • 1
  • 1
georg
  • 211,518
  • 52
  • 313
  • 390
2

Although I think what you currently have is quite pretty, something like this might work:

map(lambda m: fn(m, *args, **kwargs), filter(None, mols))

Filters out all elements from mols which evaluate to False, and then applies the function fn to these elements.

Time complexity for the algorithm is O(n).

If your mols is really large you might want to use itertools:

from itertools import imap, ifilter

list(imap(lambda m: fn(m, *args, **kwargs), ifilter(None, mols)))
msvalkon
  • 11,887
  • 2
  • 42
  • 38
  • The same comment here - is there any benefit instead of using your solution versus mine? – mnowotka Feb 14 '14 at 10:43
  • @mnowotka I doubt it. Using itertools might be beneficial speed wise if you've got a huge list of things to process. Your version is good as it is. – msvalkon Feb 14 '14 at 10:48