Python3中的单行减少

时间:2017-05-19 13:02:58

标签: python python-3.x python-2.x reduce

在Python3中,我正在寻找一种方法来计算一行一个lambda函数,该函数在两个元素上调用。假设我想计算整数列表的LCM,这可以在one line in Python2中完成:

print reduce(lambda a,b: a * b // gcd(a, b), mylist)

是否可以在一行Python3中执行相同操作(暗示,没有functools.reduce)?

在Python3中,我知道filtermapreduce已经消失。我觉得我不再需要filtermap,因为它们可以用更简洁,更清晰的方式用Python3编写,但我认为我可以找到reduce的一个很好的替代品,除了我没有找到任何。我have看过many篇文章that建议to使用functools.reduce或“write out the accumulation loop explicitly”,但我想在不导入functools的情况下这样做在一行。

如果它更容易,我应该提到我使用associativecommutative的函数。例如,在列表f上使用函数[1,2,3,4],如果计算结果将是好的:

  • f(1,f(2,f(3,4)))
  • f(f(1,2),f(3,4))
  • f(f(3,f(1,4)),2)
  • 或任何其他订单

2 个答案:

答案 0 :(得分:2)

所以我确实想出了一些东西。我不保证性能,但它是一个单独使用lambda函数的单行 - 不是来自functoolsitertools,甚至不是单个循环。

my_reduce = lambda l, f: (lambda u, a: u(u, a))((lambda v, m: None if len(m) == 0 else (m[0] if len(m) == 1 else v(v, [f(m[0], m[1])] + m[2:]))), l)

这有点难以理解,所以在这里扩展:

my_reduce = lambda l, f: (
    lambda u, a: u(u, a)) (
        (lambda v, m: None if len(m) == 0
                           else (m[0] if len(m) == 1
                                      else v(v, [f(m[0], m[1])] + m[2:])
                                )
        ),
        l
    )

测试:

>>> f = lambda a,b: a+b
>>> my_reduce([1, 2, 3, 4], f)
10
>>> my_reduce(['a', 'b', 'c', 'd'], f)
'abcd'

请检查this other post以获得有关其工作原理的更深入说明。

使用lambda函数模拟递归函数的原则,该函数的第一个参数是函数,并且本身就是。

这个递归函数嵌入在一个有效触发递归调用的函数内:lambda u, a: u(u, a)

最后,所有内容都包含在一个函数中,该函数的参数是列表和二进制函数。

my_reduce与您的代码一起使用:

my_reduce(mylist, lambda a,b: a * b // gcd(a, b))

答案 1 :(得分:1)

假设您的序列至少有一个项目,您可以像这样简单地定义reduce

def reduce(func, seq): return seq[0] if len(seq) == 1 else func(reduce(func, seq[:-1]), seq[-1])

长版本会更具可读性:

def reduce(func, seq):
    if len(seq) == 1:
        return seq[0]
    else:
        return func(reduce(func, seq[:-1]), seq[-1])

然而,递归调用和python在递归调用方面并不是很好(意味着缓慢且递归限制会阻止超过300个项目的调优序列)。更快的实施将是:

def reduce(func, seq):
    tmp = seq[0]
    for item in seq[1:]:
        tmp = func(tmp, item)
    return tmp

但由于循环,它不能放在一行。它可以通过副作用来解决:

def reduce(func, seq): d = {}; [d.__setitem__('last', func(d['last'], i)) if 'last' in d else d.__setitem__('last', i) for i in seq]; return d['last']

或:

def reduce(func, seq): d = {'last': seq[0]}; [d.__setitem__('last', func(d['last'], i)) for i in seq[1:]]; return d['last']

相当于:

def reduce(func, seq): 
    d = {} 
    for item in seq:
        if 'last' in d:
            d['last'] = func(d['last'], item)
        else:
            d['last'] = item
    return d['last']  # or "d.get('last', 0)"

这应该更快,但它并不完全是pythonic,因为单线实现中的列表理解只是因为副作用而被使用。