接前面 求balance_list【一】,这一篇来讲(不太推荐的)递归、sum();

递归

def fun_recursive(list_index, amount_list, opening):
    if list_index == 0:
        return round(opening + amount_list[0], 2)
    else:
        return round(fun_recursive(list_index - 1, amount_list, opening) + amount_list[list_index], 2)

数万交易,是不是也这样呢?

实际,递归次数多了,会报错 maximum recursion depth exceeded;

python中board函数的用法 python balance_python

这问题,咋解决?

答案:设置递归次数

python中board函数的用法 python balance_递归_02


代码如下:

import sys
sys.setrecursionlimit(3100)

这儿设置为3100次,实际我电脑在3500次左右,内存会吃不消;【下图和前面 是同样的代码,只是设置了setrecursionlimit】

python中board函数的用法 python balance_python_03

倘若 交易量真为 数万笔呢?

思路:以3000笔为一组,分组来计算 【考虑到我设置的递归限制】

def fun_recursive_2(tot):
    import random
    import math
    amount_list = random.sample(range(6000, 6000000), tot)
    opening = 5000
    Log.info('总共的订单数:{}'.format(tot))

    if len(amount_list) <= 3000:    # 将3000作为1次递归的长度
        Log.info('订单数 不超3000')
        balance_value = [fun_recursive(d, amount_list, opening) for d in range(len(amount_list))]
        Log.info(balance_value)

    else:
        ci_shu = int(math.ceil(len(amount_list) / 3000))        # 加不加int一样
        Log.info('迭代次数 {}'.format(ci_shu))
        last_list = [list() for _ in range(ci_shu)]

        for c in range(ci_shu):
            if c == 0:
                Log.info('{} - {} '.format(c * 3000, (c + 1) * 3000))

                new_list = amount_list[c * 3000:(c + 1) * 3000]
                first = [fun_recursive(i, new_list, opening) for i in range(len(new_list))]
                last_list[c].extend(first)
            else:
                Log.info('{} - {} '.format(c * 3000, (c + 1) * 3000))
                new_list = amount_list[c * 3000:(c + 1) * 3000]
                other = [fun_recursive(i, new_list, last_list[c - 1][-1]) for i in range(len(new_list))]
                last_list[c].extend(other)

        Log.info('每一笔交易后的 手上的钱数, 以3000笔为一组,:{}'.format(last_list))
        Log.info('直接sum() 计算的结果:{}'.format(sum(amount_list) + opening))
        Log.info('多次递归,最后一组 最后一笔 钱数:{}'.format(last_list[-1][-1]))

计算过程和最后的结果:

python中board函数的用法 python balance_python中board函数的用法_04

若 我只想看到balance_list,不想划分组?

def fun_recursive_3(amount_l, opening_balance):
    import math
    import sys
    sys.setrecursionlimit(3100)
    Log.info('总共的订单数:{}'.format(len(amount_l)))

    if len(amount_l) <= 3000:    # 将3000作为1次递归的长度

        balance_list = [fun_recursive(d, amount_l, opening_balance) for d in range(len(amount_l))]

    else:
        ci_shu = int(math.ceil(len(amount_l) / 3000))
        Log.info('迭代次数 {}'.format(ci_shu))

        balance_list = list()

        for c in range(ci_shu):
            if c == 0:
                Log.info('{} - {} '.format(c * 3000, (c + 1) * 3000))

                new_list = amount_l[c * 3000:(c + 1) * 3000]
                first = [fun_recursive(i, new_list, opening_balance) for i in range(len(new_list))]
                balance_list.extend(first)

            else:
                Log.info('{} - {} '.format(c * 3000, (c + 1) * 3000))

                new_list = amount_l[c * 3000:(c + 1) * 3000]
                other = [fun_recursive(i, new_list, balance_list[-1]) for i in range(len(new_list))]
                balance_list.extend(other)

        Log.info('迭代结束')

    # Log.info(balance_list)
    Log.info('直接sum() 计算的结果:{}'.format(sum(amount_l) + opening_balance))
    Log.info('多次递归,最后一笔 钱数:{}'.format(balance_list[-1]))

python中board函数的用法 python balance_递归_05

sum()

递归那一块的代码,最后面 我写的是 直接sum() 计算结果:{}'.format(sum(amount_list) + opening)。

那sum()来做这个需求是不是更好呢?

result=sum(iterable[, start])
sum() 是返回序列iterable的总和,可选参数start表示从该值开始加起来,默认为0;

def sum_balance_list(amount_list=None):
    if amount_list is None:
        amount_list_1 = [-10.5, 20.6, -15, 124.8, -156]
    else:
        amount_list_1 = amount_list
    Log.info('amount_list 获取完成')
    open_b = 50
    balance = [round(sum(amount_list_1[:a], open_b), 2) for a in range(1, len(amount_list_1) + 1)]
    print(balance)

python中board函数的用法 python balance_sum_06

如果跑几十万笔呢?我这边是 迟迟拿不到结果;(可能是我电脑配置不够的原因)

把每次传的amount_list 改动下:

def sum_balance_list_2(amount_list=None):
    import math
    if amount_list is None:
        amount_list_1 = [-10.5, 20.6, -15, 124.8, -156]
    else:
        amount_list_1 = amount_list
    Log.info('amount_list 获取完成:{}'.format(amount_list_1))

    open_b = 50

    # 设置1w次的amount做一次计算
    ci = int(math.ceil(len(amount_list_1) / 10000))
    last_list = list()

    for c in range(ci):
        Log.info('当前循环的是 {} - {}'.format(c * 10000,  (c+1) * 10000))
        am_list = amount_list_1[c * 10000: (c+1) * 10000]
        if c == 0:
            last_list = [sum(am_list[:a], open_b) for a in range(1, len(am_list) + 1)]
            Log.info(last_list)
        else:
            la = [sum(am_list[:a], last_list[-1]) for a in range(1, len(am_list) + 1)]
            Log.info(la)

            last_list.extend(la)

    Log.info('直接sum() 计算结果:{}'.format(sum(amount_list) + open_b))
    Log.info('最后一笔交易后的钱数:{}'.format(last_list[-1]))

python中board函数的用法 python balance_递归_07

递归【2】

import random
import math

import sys
sys.setrecursionlimit(3500)


am = random.sample(range(1, 600000), 350000)
op = 5000
# print(am)


def recursive(n, test_dict, amount_list, last_n, test_time):

    if n not in test_dict:
        x = n - 1
        value = recursive(x, test_dict, amount_list, last_n, test_time) + amount_list[x - test_time * 300 - 1]
        test_dict[n] = value

        if n == last_n:
            # print(test_dict)
            return test_dict

    return test_dict[n]

times = math.ceil(len(am) / 300)           # 递归深度
print(times)
test_d = dict()

for t in range(1, times + 1):
    abc = 300
    t_time = (t -1) * abc
    # print(t_time)
    new_am = am[t_time: t_time + abc]

    if t != 1:
        # print(t_time)
        op = res_n[t_time]
    # print(op)
    if t == times:
        last = len(am)
    else:
        last = abc * t

    # print(abc * t, 1 + (t-1) * abc, new_am[0] + op, last)

    res_n = recursive(last, {1 + (t-1) * abc: new_am[0] + op}, new_am, last, t-1)
    test_d.update(res_n)
print(test_d, len(test_d))

代码 为什么这样写,我没法讲清楚,因为我也是半吊子;【待我找时间 补足下 20200823留】

# 在python中的递归,可以使用字典来代替这个表

# 斐波那契数列:
# 当n = 1, 2时 f(n) = 1
# 当n > 2时  f(n) = f(n - 1) + f(n - 2)
# 比如:[1, 1, 2, 3, 5, 8, 13, 21, 34, 55...]


def fun_recursive_2(n, test_dict):
    Log.info('递归开始 {}'.format(n))

    if n in test_dict:
        Log.debug('{} 找到了'.format(n))
        Log.info(test_dict)

        return test_dict[n]
    else:
        Log.debug('这 {} 没找到'.format(n))

        value = fun_recursive_2(n - 1, test_dict) + fun_recursive_2(n - 2, test_dict)
        test_dict[n] = value
        Log.debug(test_dict)
        return test_dict[n]

new_dict = {1: 1, 2: 1}
r = fun_recursive_2(40, new_dict)       # 求第40位的数字
print(r)

部分日志如下:

python中board函数的用法 python balance_ci_08

总结

本期 从实现过程来看:我用sum() ,是有很多重复:假设500笔订单,会做了个长度为500的循环,每次遍历,都会求当前金额+前面金额的sum,但第500次求和过程,是不是已经要算出前面499次的? 正常而言,做最后一次计算,就已经得出前面过程 所有的sum了, 那个循环 完全没必要。此外,递归的用法还得再升级。