Можно ли это записать как функцию уменьшения python?

#python

#python

Вопрос:

Можете ли вы сделать это более питоническим, используя функции map и / или reduce? она просто суммирует произведения каждой последовательной пары чисел.

 topo = (14,10,6,7,23,6)
result = 0
for i in range(len(topo)-1):
    result  = topo[i]*topo[i 1]
  

Ответ №1:

Это самый приятный способ, который я могу придумать:

 import operator
sum(map(operator.mul, topo[:-1], topo[1:]))
  

Редактировать: я только что узнал, что есть лучший способ сделать это:

 import operator
import itertools

def pairwise(iterable):
    a, b = itertools.tee(iterable)
    next(b, None)
    return a, b

def sum_products(l):
    return sum(itertools.imap(operator.mul, *pairwise(l)))
  

Название парной функции указано в документации itertools.

Это быстрее и использует меньше памяти. Конечно, это менее лаконично.

Комментарии:

1. Просто используйте topo вместо topo[:-1]

2. @Kable, это не одно и то же… topo[-1] удаляет последний элемент.

3. Хотя topo вместо topo[:-1] на Python 2 для map это не сработает, с imap from itertools это будет нормально работать, и я полагаю, что это также будет нормально работать на Python 3.

4. agf, хотя вы можете это сделать, на самом деле это не самый ясный или кратчайший способ.

Ответ №2:

Вы можете использовать map и reduce подобным образом, но я не уверен, что это более питоническое:

 reduce( lambda x, y: x   y, map( lambda x, y: x * y, topo[:-1], topo[1:]) )
  

Вероятно, проще это выражение sum generator:

 sum(topo[x] * topo[x 1] for x in xrange(len(topo)-1))
  

Комментарии:

1. Спасибо, мне нравится ваша вторая.

2. Другим способом использования sum было бы sum(a * b for a, b in zip(topo[:-1], topo[1:]))

Ответ №3:

Это работает:

 mult = lambda (x, y): x * y
pairs = zip(list(topo), list(topo)[1:])
result = sum(map(mult, pairs))
  

но, вероятно, это сложнее понять.

Комментарии:

1. Вместо определения mult просто from operator import mul

2. Я думаю, что на самом деле это не работает, потому что мой лямбда принимает кортеж…

3. @Ben: Просто используйте map с несколькими итерациями: sum(map(mul, topo[:-1], topo[1:]))

Ответ №4:

Вместо map должно работать понимание списка:

 >>> topo = (14,10,6,7,23,6)
>>> sum((x*y for x,y in zip(topo[:-1],topo[1:])))
541
>>> 
  

или

 >>> sum((topo[i]*topo[i 1] for i in range(len(topo)-1)))
541
  

Комментарии:

1. В ответ Чарльза Бейли включено мое решение, и он на некоторое время опередил меня. Каким-то образом я пропустил это при первом просмотре ответов.

Ответ №5:

Я бы не назвал это pythonic, хотя это выглядит круче, reduce здесь не подходит:

 def func(first, *rest):
    return reduce(lambda (x,y),z:(x y*z,z), rest, (0,first))[0]
  

Обратите внимание, что (x,y),z используется только 2.x.

Ответ №6:

С помощью reduce и Python < 3.x:

 from itertools import tee, izip

#recipe from http://docs.python.org/library/itertools.html#recipes
def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return izip(a, b)

reduce(lambda s, (x, y):s   x * y, pairwise(topo), 0)
  

с помощью map:

 from operator import mul
from itertools import tee

a, b = tee(topo)
next(b, None)

sum(map(mul, a, b))
  

Ответ №7:

это также может дать ваш ответ

 a= [14,10,6,7,23,6]
reduce(lambda a,b: a b,  map(lambda (x,y): x*y, map(lambda i:(a[i],a[i 1]), range(len(a)-1))  ) )