zoukankan      html  css  js  c++  java
  • 迭代器与生成器 (03)

    项目快延期了, 一个人干一个项目, 真的是有点难受, 好在大头的数据处理宽表已经 用 sql 拼接出来了, 写了5个大视图拼接了一张物理宽表...也是第一次写过那么长的 sql 了, 心得就是硬怼出来的, 现都还谈不上优化, 能基本怼出来就已经很不错了, 对于目前的我而已. 其实更多的是已经有了的编程思维和sql 思维, 这两个完全不太一样的东西的碰撞吧, 多花点时间, 掌握窍门就会快很多.

    现在用的是 mysql 和 IQ, 主要是 IQ, 我写的逻辑其实还是 mysql 风格的, 就很多嵌套, 和子查询, 表关联. 这些步骤都是必须要的, 其实更多是像在硬怼, 但最终还是能够整出来的. 跟面向过程编程的感觉是一样的, 我是觉得特别锻炼逻辑能力的.

    然后也逐渐发现呢, 其实 sql 顺序, 会让你感到, 并不是严格按照 from , on, join, where, group by, having, select , distinct, group by, order by limit .. 这样的, 数据库引擎会自动做优化. 当然不同的商业公司的产品可能会不一样的.

    简单来个小栗子, 还是以学生表为例.

    select s_name as 姓名 from student where 姓名 = '星落'
    
    • 在 mysql 中, 这样写是不可以的, 因为 '姓名' 在 student 表中没有定义的
    • 在 IQ 中, 是可以的, 它在执行前, 会把 where 的 '姓名' 类似用以 s_name 替换, 说明引擎是有优化的

    但是在 IQ 中, 如果 select 里面有 计算字段, 函数参与的字段, 就会找不到, 就让我很奇怪, 到底是优化还是没有

     select 
      s_id as 学号,
      avg(score) as 平均成绩
     from score 
     group by 学号
       having 平均成绩 > 70
    
    
    学号     平均成绩
    0001	89.6667
    0003	80.0000
    

    你会发现, 会给你一种感觉, 执行了 select 的部分, 再执行 group by 的. 也会有一种, 动态编程语言的感觉, 比如 Python 或者 JavaScript, 就执行的时候, 会自己去按一定顺序进行搜索. 具体是怎么实现的, sql 这块我目前也不清楚, 唯一能做的就是去写, 去尝试,如果不行就再再外面, 嵌套一层, 哈哈哈 .

    扯远了, 本来是要在看一波迭代器的.

    迭代器切片

    需求

    不通过把迭代器对象全部 list 等方式 "放出来" , 太消耗内存, 只想切片来取一部分.

    方案

    通过 itertools.islice () 来实现对迭代对象的切片. 不能用 [ ] 这种方式哦

    def count(n):
        """从 n 开始往后计数, 步长为1"""
        while True:
            yield n
            n += 1
    # test
    g = count(0)
    g[10:20]
    
    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    <ipython-input-1-72a548c692de> in <module>
          6 
          7 g = count(0)
    ----> 8 g[10:20]
    
    TypeError: 'generator' object is not subscriptable
    

    生成器 generator 是不能直接来切片的, 用 itertools.islice( )

    import itertools 
    
    for i in itertools.islice(g, 1, 10):
        print(i)
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    

    其实很好理解, 生成器对象是不能用咱的标准切片的, 因为它的长度, 事先我们并不知道, 而且也没有实现索引.

    函数 itertools.islice( ) 会返回一个可以生成指定元素的迭代器, 通过 遍历并丢弃 直到切片开始索引位置的所有元素, 然后才一个个地返回元素, 直到结束嘛.

    需要注意的是, islice() 函数会消耗掉传入迭代器中的数据. 必须考虑到, 迭代器是一个不可逆的事实, 就像时间, 流逝了就永远不会再回来.

    排列组合的迭代

    需求

    迭代遍历一个集合中, 元素的所有可能性 (排列或者组合)

    方案

    通过 itertools 内置模块的 permutations( ), combinations( ), combinations_with_replacement() 这三个已经造好的轮子来计算集合元素的排列组合.

    我之前有自己实现过排列组合, 有点忘了是咋搞了, 当时也是参考网上的大佬, 就写起来蛮复杂其实, 留个小 todo, 我先学搬砖, 后面再看看怎么自己来实现一遍吧.

    首先是 permutations () 排列嘛, 跟咱数学的东西是一样的. 它接收一个集合对象, 并产生一个元组序列, 是无序的.

    从n个元素中取m个元素, 排列数有 : (A_n^m = n(n-1)(n-2)...(n-m+1) = frac {n!} {(n-m)!})

    from itertools import permutations
    
    lst = ['a', 'b', 'c'] 
    
    # 是一个可迭代对象, 生成器 <itertools.permutations at 0x1f41a20da40>
    
    for p in permutations(lst):
        print(p)
    
    ('a', 'b', 'c')
    ('a', 'c', 'b')
    ('b', 'a', 'c')
    ('b', 'c', 'a')
    ('c', 'a', 'b')
    ('c', 'b', 'a')
    

    还可以指定长度的所有排列, 可以传参, 这就很厉害了. 反正暂时我是不会写, 搬砖我是专业的.

    for p in permutations(lst, 2):
        print(p)
    
    ('a', 'b')
    ('a', 'c')
    ('b', 'a')
    ('b', 'c')
    ('c', 'a')
    ('c', 'b')
    

    同样的, 组合 combinations() 也是类似的用法, 它返回一个集合元素中的所有组合.

    从 n 个 中 取 m 个元素, 组合数有: (C_n^m = frac {n!}{m!(n-m)!}) 推导过程是地推的, 这里不讲了, 留到概率论部分的笔记吧.

    lst = ['a', 'b', 'c']
    
    for c in itertools.combinations(lst, 3):
        print(c)
        
    print() 
    
    print("从3个中取2个, 一共有: ")
    for c in itertools.combinations(lst, 2):
        print(c)
    
    ('a', 'b', 'c')
    
    从3个中取2个, 一共有: 
    ('a', 'b')
    ('a', 'c')
    ('b', 'c')
    

    最后这个 combinations_with_replacement( ) 就咱说的,可放回抽样.

    对于 combinations 来说, 元素的顺序其实无所谓的, 都只是一个. 因此在计算组合的时候, 一旦元素被选取, 就会从候选中给剔除掉. 而如果是要实现可放回抽样, 就要这样玩:

    for c in itertools.combinations_with_replacement(lst, 3):
        print(c)
    
    ('a', 'a', 'a')
    ('a', 'a', 'b')
    ('a', 'a', 'c')
    ('a', 'b', 'b')
    ('a', 'b', 'c')
    ('a', 'c', 'c')
    ('b', 'b', 'b')
    ('b', 'b', 'c')
    ('b', 'c', 'c')
    ('c', 'c', 'c')
    

    小结

    • 迭代器对象的切片用 itertools.islice () 方法来实现, 偶尔是会用的
    • 排列组合的迭代对象 也用 itertools 里面的 permutations( ), combinations( ), combinations_with_replacement()
    • itertools 这个内置模块很香, 值得搬砖, 同时也抽空自己来写一遍排列组合原理, 和数学推导
  • 相关阅读:
    C# WinForm程序退出的方法
    SpringCloud 微服务框架
    idea 常用操作
    Maven 学习笔记
    SpringBoot 快速开发框架
    html 零散问题
    Java方法注释模板
    Seating Arrangement
    hibernate 离线查询(DetachedCriteria)
    hibernate qbc查询
  • 原文地址:https://www.cnblogs.com/chenjieyouge/p/13138660.html
Copyright © 2011-2022 走看看