Python重复:python是否有基于条件/ lambda的重复方法?

时间:2016-02-07 16:39:00

标签: python lambda

我有以下功能

def handle(x):
    if is_odd(x):
        return x * 3 + 1
    return x // 2

我希望运行它,将句柄(x)返回的值反复输入到自身,直到它返回1

即。 handle(... handle(handle(handle(x)))...)直到链中的一个返回1

repeat(handle(x), lambda x: x != 1)

我想写这样的东西:

(let n = handle(x) until n != 1)

基本上我想存储句柄的输出,直到我得到1。

expression(handle(10)) = [5,
                         16,
                         8,
                         4,
                         2,
                         1]

是否有与此相当的生成器表达式?或者我可以使用functools.repeat方法吗?

为了清楚起见,我想避免直接使用带有yield或递归的for循环。我想在内置功能中使用python来解决这个问题,不包括for循环/递归。

4 个答案:

答案 0 :(得分:2)

使用Collat​​z Conjecture不需要任何神奇的方法,只需编写常规循环

def expression(n):
  result = [n]
  while n > 1:
    n = handle(n)
    result.append(n)
  return result

特别是你可以把它变成一个发电机

def expression_gen(n):
  yield n
  while n > 1:
    n = handle(n)
    yield n

显然你可以通过

进行参数化
def expression_gen(n, handle, end):
  yield n
  while not end(n):
    n = handle(n)
    yield n

你可以用lambda表达式作为句柄/结束来调用它。

答案 1 :(得分:2)

我猜你可以使用itertools.accumulateitertools.takewhile

from itertools import accumulate, takewhile, repeat

def collatz(n):
    seq = accumulate(repeat(n), lambda x,_: handle(x))
    return list(takewhile(lambda x: x!=1, seq)) + [1]

给出了

>>> collatz(5)
[5, 16, 8, 4, 2, 1]
>>> collatz(17)
[17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]

但我有一个共同观点,即我不明白这一点。甚至官方文档也列出了很多recipes,它们可以很方便地使用非内置的iterables;我不明白为什么你不能只定义像

这样的东西
def repeat_until(fn, x, cond):
    while True:
        yield x
        if cond(x): break
        x = fn(x)

继续你的一天。我知道你已经说过你不想出于某种原因明确使用yield,但仅仅因为你说你想要的东西并不意味着你想要的东西是有意义的。 : - )

答案 2 :(得分:1)

首先,我认为这是使用生成器和while循环的规范方法。

def handle(x):
    while x != 1:
        x = x*3 + 1 if x%2 else x//2
        yield x

演示:

>>> list(handle(10))
[5, 16, 8, 4, 2, 1]

如果您的Python版本支持它,那么接近您正在寻找的另一个选项是使用递归和yield from语法:

def handle(x):
    if x!= 1:
        x = x*3 + 1 if x%2 else x//2
        yield x
        yield from handle(x)

但是这种方法存在问题,这正在炸毁堆栈:

>>> for x in handle(1E1000): pass
[...]
RecursionError: maximum recursion depth exceeded in comparison

答案 3 :(得分:0)

您可以使用while循环:

def handle(num):
    while num > 1:
        if num % 2 == 0:
            num //= 2
            print(num)
        else:
            num = 3 * num + 1
            print(num)


if __name__ == '__main__':
    handle(10)