2

Given a list [a, b, c, d] I'd like to call a function foo() which returns a number and multiply the return values:

result = foo(a, b) * foo(b, c) * foo(c, d)

What would be the pythonic one-liner for this? The C-Programmer inside me would start fiddling about with indices and for loops but I know there must be a better way..

frans
  • 8,868
  • 11
  • 58
  • 132
  • By the way, the functional approach is not necessarily the most "pythonic". Guido van Rossum is known not to encourage the functional approach (`reduce` is no longer a built-in, and `map` almost disappeared with Python 3). A `for` loop is probably the clearest way to go. – Delgan May 21 '17 at 09:30
  • Do you have a nice example which works without initializing a result, iterating from `0 .. range(len(list)-1))` and manually combining the results? (would be 3 ugly lines). If this would be the answer I disagree with Guido. – frans May 21 '17 at 09:36
  • Initializing a variable is fine. `product = 1; for a, b in zip(lst, lst[1:]): product *= foo(a, b)`. – Delgan May 21 '17 at 09:40
  • More general than the answer: `reduce(lambda s, f: list(map(f, *pairs(s))), [operator.add], range(1, 5))` -> [3, 7], or with two applications of binary functions: `reduce(lambda s, f: list(map(f, *pairs(s))), [operator.add, operator.mul], range(1, 5))` -> [21] – Reut Sharabani May 21 '17 at 09:43
  • Wow, I'd need a LOT of coffee to guess what happens here.. – frans May 21 '17 at 09:45
  • @frans This is why one-liner are not always "pythonic". ^^ – Delgan May 21 '17 at 09:53
  • Well - in my eyes `reduce(mul, map(foo, my_list, my_list[1:]))` is not *very* intuitive because it's hard to see what exactly `map` does but it's short and expresses what I want to do: "multiply the results of `foo()` for every pair in `my_list`". So in my opinion what I want to do *is* functional in the first place and thus it's more intuitive than an explicit `for` loop.. – frans May 21 '17 at 10:01
  • 1
    "Avoid answering questions in comments." Sorry, but if you unnecessarily block question, what am I supposed to do? I truly despise the practice of marking questions as duplicates. More often than not, I've found that decision to be rather subjective and based on arrogance. If someone asks what seems to be the same question again, it's because they either didn't find the first question, or because it was not the same question after all. The original poster should have the option to decide whether they want to close (or remove) a question once pointed out that it is a duplicate. – ACz May 21 '17 at 10:19
  • For things that are algorithmically simple, I like to rely on built-in stuff rather than additional modules. Having said that, this is how I would solve this particular version of this problem: – ACz May 21 '17 at 10:21
  • For things that are algorithmically simple, I like to rely on built-in stuff rather than additional modules. Having said that, this is how I would solve this particular version of this problem: `def product(iterable): if iterable: result = iterable[0]; for elmt in iterable[1:]: result *= elmt; #endfor; return result; else: return None; #endelse; #enddef; result = product([foo(arr[i], arr[i+1]) for i in range(len(arr) - 1)])` – ACz May 21 '17 at 10:33

1 Answers1

4

Here you have a functional aproach:

import operator
from functools import reduce #only python3
result = reduce(operator.mul, map(foo, l, l[1:]))

It can be improve usin some itertools functions as imap for better performance in python2

Yavar
  • 11,883
  • 5
  • 32
  • 63
Netwave
  • 40,134
  • 6
  • 50
  • 93
  • @Delgan indeed i meant, thanks for the fix. – Netwave May 21 '17 at 09:26
  • I don't agree with Guido - there might be nicer ways to functionally express what I want to do but this approach is **far** more readable (and exception safe!) than explicitly looping through the list.. – frans May 21 '17 at 10:05