如何重写这个简短的算法,使其更有效?

时间:2016-07-26 23:44:11

标签: algorithm function loops statistics coding-efficiency

任何方法编写一个功能上等同于而不包含循环的函数?

Python代码:

luck = 0.3
tries = 200000000

getStrikes():
    strikes = 0
    for i in range(tries):
        if random.random() <= luck:
            strikes++;
    return strikes

好的,抱歉我在过去5分钟内编辑过原始帖子的垃圾邮件。我现在就停止了,因为我根据收到的反馈澄清了我想问的内容。

2 个答案:

答案 0 :(得分:3)

strikesbinomial distribution的随机变量。 scipy支持从此分布中抽样,而不是总计大量Bernouilli trials

以下是一个例子:

from scipy.stats import binom

luck = 0.3
trials = 200000000
print binom(trials, luck).rvs()

尽管进行了大量试验,但这几乎是立即进行的。

答案 1 :(得分:2)

在函数式编程中有几种工具,比如折叠和列表/生成器理解,但最基本的想法是递归。

因此,例如,对于getTotal():

getTotal(sides, dice):
    if dice == 0:
        return 0
    else
        return rand.int(sides) + getTotal(sides, dice - 1)

遗憾的是,这个函数对你的具体例子不起作用,因为堆栈会在我们结束之前很久就会溢出。我们通过使函数tail递归来解决这个问题,因此您可以使用tail call optimization(并非所有语言都使用此功能,但几乎所有函数语言都使用此功能)。这是通过添加一个以0开头的累加器变量来实现的:

getTotal(sides, dice, accumulator = 0):
    if dice == 0:
       return accumulator
    else
       return getTotal(sides, dice - 1, accumulator + rand.int(sides))

在这个版本的函数中,递归调用是一个&#34;尾调用&#34;,这意味着它是该函数最后的事情(在以前的版本中不是这种情况) ,添加是最后发生的事情,所以它不是尾递归)。 getSixes()版本可以用相同的方式完成,除了不仅仅是将骰子卷添加到累加器,当且仅当卷是累加器的6时,我们才加1。

然而,这种模式很常见,许多语言都有&#34;快捷方式&#34;为此,即fold。由于我不想发明一堆符号,我只想在Python中编写下一个例子:

def getTotal(sides, dice):
    add = lambda x,y: x + y
    return reduce(add, (rand.int(sides) for _ in range(dice)))

reduce是左侧折叠的python名称,add是我们正在折叠的函数。 (rand.int(sides) for _ in range(dice))部分是一个懒惰的生成器(即我们需要它们,而不是一开始就是一次)生成随机数,特别是dice个数。

函数式编程的另一个技巧是&#34; filter&#34;基于某些布尔函数的值。我们可以通过这种方式解决getSixes()

def getSixes(sides, dice):
    condition = lambda x: x == 6
    return len(filter(condition, (rand.int(sides) for _ in range(dice))))

所有这些方式都具有与使用循环相同的内存/速度特性(即,相同的大O特性),尽管使用循环通常更快一些,因为开销更少。

编辑:此答案更适用于您编辑之前的问题版本,但这个想法与您的新版本非常相似。

编辑2:原始标题是&#34;如何在不使用循环的情况下重写此问题&#34;这是我的答案所适用的,如何在不使用循环的情况下执行此操作。我没有意识到你想要一个数学公式,为什么我的答案根本不适用。