小白学习日记2_Python生成器(Generator)/杨辉三角形(Tirangles)_2020年5月17日

从昨天下午学完列表生成式就开始琢磨这个 生成器 + 列表生成式 输出杨辉三角

话不多说先放廖神的学习链接:https://www.liaoxuefeng.com/wiki/1016959663602400/1017318207388128

起初还在抱怨廖神每次给的题都这么头疼,第一次是递归函数的汉诺塔(说来惭愧,我现在也没想明白哈哈哈),这次给的杨辉三角(又称帕斯卡三角)虽然看的明白但是也开始也不知道咋用代码写出来,后来吧经过长时间的看回答搜索问题终于弄懂了,而且还整明白了其他几个没掌握的知识点。所以举一反三真的很重要,但是遇到看不明白的也要学会放下(比如我的汉诺塔TAT)。

废话完了开始正题:

生成器按我的理解就是将List、Dic、Tuple这些元组中有规律的那一部分不以数据的形式储存,而是仅储存其算法,因此可以节约大量的内存空间,毕竟List输出的是一串数据会占用极大的内存空间

而生成器输出的只是一串内存的位置:<generator object triangles at 0x000001FDA210E510>,在这个地方保留了算法,需要调用的时候就重新计算一下,当然这些都只是性质上的,那么实际操作上应该如何进行呢?

生成Generator有两种方式,一种是将列表生成式的 [ ] 直接重新赋值改为 ( ) 就成为了一个Generator,另一种是接下来要说到的使用 yield 语法。

第一种举例(这里直接引用廖神的举例,我脑子不够就不做无谓的浪费了):

>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x1022ef630>

可以很明显的看到仅仅是改变了括号的形式,但是类型和输出结果都完全变化了。

第二种就直接跟对杨辉三角的理解来说了吧,首先放上杨辉三角:

          1
         / \
        1   1
       / \ / \
      1   2   1
     / \ / \ / \
    1   3   3   1
   / \ / \ / \ / \
  1   4   6   4   1
 / \ / \ / \ / \ / \
1   5   10  10  5   1

这个 / 和 \ 都可以理解为合并,源头的数合并为尽头的数。 

百度百科中Python部分的代码写的比我的有灵性多了,可以参考参考:https://baike.baidu.com/item/%E6%9D%A8%E8%BE%89%E4%B8%89%E8%A7%92/215098?fromtitle=%E6%9D%A8%E8%BE%89%E4%B8%89%E8%A7%92%E5%BD%A2&fromid=5409623&fr=aladdin#4_10

我琢磨的代码是:

def triangles_one(max):
    L = [1]
    if max == 1:
        return L
    L = [0, 1, 0]
    n = 1
    while n < max:
        n = n + 1
        L1 = [0]
        for i in range(len(L)-1):
            L1.append(L[i]+L[i+1])
        L1.append(0)
        L = L1
    return L[1:len(L)-1]

来说一下这个代码的思路,我将每一行最前都加了个0(看了百度百科后发现这一步是多余的),就是一开始就定义无论如何while我的L1都是从 [0] 干起,于是每行的一个数一定是0,第二个数一定是 0 号位和 1 号位相加。

于是有了 L1.append(L[i]+L[i+1]) ,中间的那句 for i in range(len(L)-1) 就是规定了这个 append 的数是从上一个 L 的 0 号位和 1 号位相加开始的。同时我也是才知道range不规定起始位置就从0开始取,同样的range第一篇提到过是包头不含尾的。

加工完中间的数据,我们最后一个数如果不在上一个L的末尾进行 append(0) 就会使 L1.append(L[i]+L[i+1]) 中的 L[i+1] 这个超出,因为 i 是最后一个数,所以需要在末尾进行 append(0) 这个操作。

最后因为首尾各加了一个多余的0用来辅助(这里的思路就很想Excel里的辅助列),但是在正式的结果中是不需要这个辅助的,于是我们利用list的取数规则 L[1:len(L)-1] 对L进行去头舍尾。

但是这个代码只能输出max那一层的结果,无法顺利的提取全部的结果(比如要求要1至5层每一层的结果就没办法了),很没有灵性,那稍微改一下:

def triangles_each(max):
    print([1])
    if max == 1:
        return 'done'
    L = [0, 1, 0]
    n = 1
    while n < max:
        n = n + 1
        L1 = [0]
        for i in range(len(L)-1):
            L1.append(L[i]+L[i+1])
        L1.append(0)
        L = L1
        print(L[1:len(L)-1])
    return 'done'

print(triangles(5))

#输出:
#[1]
#[1, 1]
#[1, 2, 1]
#[1, 3, 3, 1]
#[1, 4, 6, 4, 1]
#done

但是这样需要不停的将数据加到list中(你没有看到是因为我懒....),也占用内存,很不划算,而且代码很笨重,于是这个时候我们终于可以进入到正题了,使用 yield 语句将这个函数变为一个 Generator 。

代码如下:

def triangles_grt(max):
    yield [1]
    L = [0, 1, 0]
    n = 1
    while n < max:
        n = n + 1
        L1 = [0]
        for i in range(len(L)-1):
            L1.append(L[i]+L[i+1])
        L1.append(0)
        L = L1
        yield L[1:len(L)-1]

这个 yield 的意思按我的理解就是收录,就是告诉计算机你收录一下这个结果,类似list的append,yield 的英语我看了一下是屈服、停止争论,对比上面的代码每个结果都要输出,而yield了之后就保存起来了,相当于 emmm 隐忍吧哈哈。反正就是告诉计算机:闭嘴吧你,记着就好了。于是就变成了一个Generator。

 

到这里都是怎么生成Generator,以及笨办法整杨辉三角形,现在来看看我在百度百科里看到的使用列表生成式结合 yield 和我新学会的 sum 和 zip 函数(有点绕哈,但是代码这个事情吧确实不懂的时候云里雾里,懂了就是腾云驾雾哈哈哈),以下是正题,包括一些我的学习小方法:

首先放上列表生成式的结果(到目前为止每一段代码我都是现场手打出来,因为只有这样才能真正的属于自己,即使过后忘记了,但等到需要的时候也能快速的捡起来):

def triangles_cpn():
    L = [1]
    while 1:
        yield L
        L = [sum(i) for i in zip([0]+L, L+[0])]

这个里面主要用到的思维是错位相加,同时错位相加是用这个 zip 函数实现的,关于 zip 函数可以看看Runoob的教程:

https://www.runoob.com/python/python-func-zip.html

我的习惯就是拿到一个函数先在编译器里面试一下,比如这个 zip 函数,我试验了:

L = [1,2,1]
t = zip([0]+L, L+[0])

for i in t:
    print(i)

#以下是输出结果:
#(0, 1)
#(1, 2)
#(2, 1)
#(1, 0)

这个就是错位相加,不知道大家是否又发现这实际上这个输出结果就是一个错位相加,同时与上面的 L1.append(L[i]+L[i+1]) 异常神似,同时很完美缩减了行数,当然,到 zip 函数这里其实也只是实现了错位,sum 函数实现了相加,sum 会将一个list中的所有元素求和(但是这里要注意list中只能包含 float 和 int ,如果有 str 之类的就会返回一个错误)。

这个时候再去看上面的 列表生成式 + yield生成器 def 的杨辉三角形函数,就全部可以理解,并且发现很有灵性。

个人认为一段代码如果能逻辑清晰的写出来当然最好,不过能这样具有灵性的表达出来会使代码更迷人哈哈。

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值