知识点
在古典小说和传统评话中,常说武艺高强的人是“十八般武艺样样精通”,这十八般武艺是指使用“十八般兵器”的功夫和技能。哪十八般呢?
十八般兵器在武术界中最普遍的说法是:刀、枪、剑、戟、斧、钺、钩、叉、鞭、锏、锤、抓、镗、棍、槊、棒、拐、流星。
汉武于元封四年(公元前107),经过严格的挑选和整理,筛选出18种类型的兵器:矛、镗、刀、戈、槊、鞭、锏、剑、锤、抓、戟、弓、钺、斧、牌、棍、枪、叉。
三国时代,著名的兵器鉴别家吕虔,根据兵器的特点,对汉武帝钦定的“十八般兵器”重新排列为九长九短。九长:戈、矛、戟、槊、镗、钺、棍、枪、叉;九短:斧、戈、牌、箭、鞭、剑、锏、锤、抓。
明代《五杂俎》和清代《坚集》两书所载,“十八般兵器”为弓、弩、枪、刀、剑、矛、盾、斧、钺、戟、黄、锏、挝、殳(棍)、叉、耙头、锦绳套索、白打(拳术)。后人称其为“小十八般”。
迭代器
迭代器的最大优势就是延迟计算按需使用,节省内存空间、提高运行效率。
迭代工具库 itertools 中共有18个函数,恰好似“迭代界”的十八般兵器,掌握了这些功夫和技能也可以说是“十八般武艺样样精通”!:
>>> import itertools >>> tools = [func for func in dir(itertools) if func[0]>='a'] >>> len(tools) 18 >>> tools ['accumulate', 'chain', 'combinations', 'combinations_with_replacement', 'compress', 'count', 'cycle', 'dropwhile', 'filterfalse', 'groupby', 'islice', 'permutations', 'product', 'repeat', 'starmap', 'takewhile', 'tee', 'zip_longest']
1. 累加器 accumulate
>>> import itertools as it >>> it.accumulate(range(1,11)) <itertools.accumulate object at 0x0A0C9988> >>> list(it.accumulate(range(1,11))) [1, 3, 6, 10, 15, 21, 28, 36, 45, 55] >>> list(it.accumulate([1]*10)) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> >>> L = [1]*10 >>> list(it.accumulate(L)) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> L = list(it.accumulate(L)) >>> list(it.accumulate(L)) [1, 3, 6, 10, 15, 21, 28, 36, 45, 55] >>>
1乘2乘3...一直乘到n有阶乘运算 n! ,但1加2加3...一直加到n,一般都没有定义“累和”运算,还需循环来计算。现在有了这个函数可以代替用用的,比如1加到100:
1. >>> list(it.accumulate(range(1+100)))[-1] 2. 5050 3. >>>
不用此库函数的代码实现:
>>> a = [1 for _ in range(10)] >>> a [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] >>> for i,n in enumerate(a): if i:a[i] += a[i-1] # 或 if i+1<len(a):a[i+1] += n >>> a [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> for i in range(1,len(a)): a[i] += a[i-1] # 这样原始的比较简洁 >>> a [1, 3, 6, 10, 15, 21, 28, 36, 45, 55] >>>
还有另外两个参数 func 和 initial,可以完成其它自定义运算:
>>> list(it.accumulate([1,2,3,4],lambda x,y:x+y)) [1, 3, 6, 10] >>> list(it.accumulate([1,2,3,4],lambda x,y:x*y)) [1, 2, 6, 24] >>> list(it.accumulate([1,2,3,4],lambda x,y:x-y)) [1, -1, -4, -8] >>> list(it.accumulate([1,2,3,4],lambda x,y:y-x)) [1, 1, 2, 2] >>> import operator >>> list(it.accumulate([1,2,3,4],operator.add)) [1, 3, 6, 10] >>> list(it.accumulate([1,2,3,4],operator.sub)) [1, -1, -4, -8] >>> list(it.accumulate([1,2,3,4],operator.mul)) [1, 2, 6, 24] >>> list(it.accumulate([1,2,3,4], operator.mul, initial=2)) [2, 2, 4, 12, 48] >>>
2. 连接器 chain
连接多个迭代器,或其它可迭代对象
>>> import itertools as it >>> it.chain(range(3),[3,4,5],{6,7},(i for i in range(8,11))) <itertools.chain object at 0x0A0BF3B8> >>> list(it.chain(range(4),[4,5],{6,7},(i for i in range(8,11)))) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>>
3. 组合器 combinations
from itertools import combinations as comb >>> comb1 = comb(range(4), 3) >>> list(comb1) [(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)] >>> comb2 = comb(range(1,6), 3) >>> list(comb2) [(1, 2, 3), (1, 2, 4), (1, 2, 5), (1, 3, 4), (1, 3, 5), (1, 4, 5), (2, 3, 4), (2, 3, 5), (2, 4, 5), (3, 4, 5)] >>> comb3 = comb(range(1,6), 4) >>> list(comb3) [(1, 2, 3, 4), (1, 2, 3, 5), (1, 2, 4, 5), (1, 3, 4, 5), (2, 3, 4, 5)] >>>
4. 可重复组合器 combinations_with_replacement
>>> from itertools import combinations_with_replacement as Comb2 >>> comb1 = Comb2(range(4), 3) >>> list(comb1) [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 0, 3), (0, 1, 1), (0, 1, 2), (0, 1, 3), (0, 2, 2), (0, 2, 3), (0, 3, 3), (1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 2, 2), (1, 2, 3), (1, 3, 3), (2, 2, 2), (2, 2, 3), (2, 3, 3), (3, 3, 3)] >>> comb2 = Comb2(range(1,6), 3) >>> list(comb2) [(1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 1, 4), (1, 1, 5), (1, 2, 2), (1, 2, 3), (1, 2, 4), (1, 2, 5), (1, 3, 3), (1, 3, 4), (1, 3, 5), (1, 4, 4), (1, 4, 5), (1, 5, 5), (2, 2, 2), (2, 2, 3), (2, 2, 4), (2, 2, 5), (2, 3, 3), (2, 3, 4), (2, 3, 5), (2, 4, 4), (2, 4, 5), (2, 5, 5), (3, 3, 3), (3, 3, 4), (3, 3, 5), (3, 4, 4), (3, 4, 5), (3, 5, 5), (4, 4, 4), (4, 4, 5), (4, 5, 5), (5, 5, 5)] >>>
5. 排列器 permutations
>>> import itertools as it >>> list(it.permutations([1,2,3])) [(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)] >>> # 数字1、2、3能组成哪些三位数? >>> [i[0]*100+i[1]*10+i[2] for i in it.permutations([1,2,3])] [123, 132, 213, 231, 312, 321] >>>
6. 压缩器 compress
按照真值表来精简迭代器,筛选出部分值
1. >>> import itertools as it 2. >>> i = it.compress(range(6), (1,1,0,0,1,0)) 3. >>> list(i) 4. [0, 1, 4] 5. >>>
7. 切片器 islice
>>> import itertools as it >>> islice = it.islice(range(100),0,9,2) >>> list(islice) [0, 2, 4, 6, 8] >>> iSlice = it.islice(range(1,100),0,9,2) >>> list(iSlice) [1, 3, 5, 7, 9] >>> # 可以不指定起始和步长,直接指定个数 >>> list(it.islice(range(1,100),10)) [1, 11, 21, 31, 41, 51, 61, 71, 81, 91] >>>
8. 计数器 count
因为生成器只提供说法不是数据集,直接用 list(count1)会死循环的,可以用islice()指定一下个数。
>>> import itertools as it >>> count1 = it.count(start=0,step=3) >>> list(it.islice(count1,12)) [0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33] >>> count2 = it.count(start=100,step=-2) >>> list(it.islice(count2,10)) [100, 98, 96, 94, 92, 90, 88, 86, 84, 82] >>>
9. 循环器 cycle
>>> import itertools as it >>> list(it.islice(it.cycle('ABC'),10)) ['A', 'B', 'C', 'A', 'B', 'C', 'A', 'B', 'C', 'A'] >>> list(it.islice(it.cycle([1,2,3,4]),10)) [1, 2, 3, 4, 1, 2, 3, 4, 1, 2] >>>
10. 重复器 repeat
>>> import itertools as it >>> list(it.repeat(5,10)) [5, 5, 5, 5, 5, 5, 5, 5, 5, 5] >>> list(it.repeat([1,2],5)) [[1, 2], [1, 2], [1, 2], [1, 2], [1, 2]] >>>
11. 舍真器 dropwhile
舍弃不满足条件的元素,但当条件不满足即停止筛选
>>> import itertools as it >>> lst = [1,3,5,2,4,6,10,11,7,8,12,15] >>> list(it.dropwhile(lambda i:i<9,lst)) [10, 11, 7, 8, 12, 15] >>> list(it.dropwhile(lambda i:i%2,lst)) [2, 4, 6, 10, 11, 7, 8, 12, 15] >>>
12. 留真器 takewhile
留下满足条件的元素,但当条件不满足即停止筛选
>>> import itertools as it >>> list(it.takewhile(lambda i:i<6, range(10))) [0, 1, 2, 3, 4, 5] >>> lst = [1,3,5,2,4,6,10,11,7,8,12,15] >>> list(it.takewhile(lambda i:i<11,lst)) [1, 3, 5, 2, 4, 6, 10] >>> list(it.takewhile(lambda i:i%6,lst)) [1, 3, 5, 2, 4] >>>
13. 筛假器 filterfalse
舍弃满足条件的所有元素,留下所有不满足条件的
>>> import itertools as it >>> lst = [1,3,5,2,4,6,10,11,7,8,12,15] >>> list(it.filterfalse(lambda i:i<9,lst)) [10, 11, 12, 15] >>> list(it.filterfalse(lambda i:i%2,lst)) [2, 4, 6, 10, 8, 12] >>>
14. 分组器 groupby
>>> import itertools as it >>> group = it.groupby(range(20), lambda i:not 8<i<16) >>> for i,j in group: print(i,list(j)) True [0, 1, 2, 3, 4, 5, 6, 7, 8] False [9, 10, 11, 12, 13, 14, 15] True [16, 17, 18, 19] >>>
15. 乘积器 product
>>> import itertools as it >>> list(it.product('ABC',(1,2))) [('A', 1), ('A', 2), ('B', 1), ('B', 2), ('C', 1), ('C', 2)] >>> [''.join(i) for i in list(it.product('ABC','12'))] ['A1', 'A2', 'B1', 'B2', 'C1', 'C2'] >>> [''.join(i) for i in list(it.product('ABCD','123'))] ['A1', 'A2', 'A3', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3', 'D1', 'D2', 'D3'] >>> # 第二参数: repeat = n , 默认值为1 >>> list(it.product('ABC',[1],repeat=2)) [('A', 1, 'A', 1), ('A', 1, 'B', 1), ('A', 1, 'C', 1), ('B', 1, 'A', 1), ('B', 1, 'B', 1), ('B', 1, 'C', 1), ('C', 1, 'A', 1), ('C', 1, 'B', 1), ('C', 1, 'C', 1)] >>> [''.join(i) for i in list(it.product('ABC',repeat=2))] ['AA', 'AB', 'AC', 'BA', 'BB', 'BC', 'CA', 'CB', 'CC'] >>> [''.join(i) for i in list(it.product('ABC','ABC',repeat=2))] ['AAAA', 'AAAB', 'AAAC', 'AABA', 'AABB', 'AABC', 'AACA', 'AACB', 'AACC', 'ABAA', 'ABAB', 'ABAC', 'ABBA', 'ABBB', 'ABBC', 'ABCA', 'ABCB', 'ABCC', 'ACAA', 'ACAB', 'ACAC', 'ACBA', 'ACBB', 'ACBC', 'ACCA', 'ACCB', 'ACCC', 'BAAA', 'BAAB', 'BAAC', 'BABA', 'BABB', 'BABC', 'BACA', 'BACB', 'BACC', 'BBAA', 'BBAB', 'BBAC', 'BBBA', 'BBBB', 'BBBC', 'BBCA', 'BBCB', 'BBCC', 'BCAA', 'BCAB', 'BCAC', 'BCBA', 'BCBB', 'BCBC', 'BCCA', 'BCCB', 'BCCC', 'CAAA', 'CAAB', 'CAAC', 'CABA', 'CABB', 'CABC', 'CACA', 'CACB', 'CACC', 'CBAA', 'CBAB', 'CBAC', 'CBBA', 'CBBB', 'CBBC', 'CBCA', 'CBCB', 'CBCC', 'CCAA', 'CCAB', 'CCAC', 'CCBA', 'CCBB', 'CCBC', 'CCCA', 'CCCB', 'CCCC'] >>>
16. 映射器 starmap
>>> import itertools as it >>> list(it.starmap(str.isupper, 'AbCDefgH')) [True, False, True, True, False, False, False, True] >>> list(it.starmap(lambda a,b,c:a+b+c,([1,2,3],[4,5,6],[7,8,9]))) [6, 15, 24] >>> list(it.starmap(lambda *a:sum(a),[range(5),range(10),range(101)])) [10, 45, 5050] >>>
17. 元组器 tee
返回多个迭代器的元组
>>> import itertools as it >>> [list(i) for i in it.tee([1,2,3],3)] [[1, 2, 3], [1, 2, 3], [1, 2, 3]] >>> it.tee([1,2,3],3) (<itertools._tee object at 0x030711A8>, <itertools._tee object at 0x03078228>, <itertools._tee object at 0x0131FFE8>) >>>
18. 打包器 zip_longest
与内置函数zip()类似,但元素个数以最长的迭代器为准
>>> import itertools as it >>> list(it.zip_longest('ABCDE',range(1,4))) [('A', 1), ('B', 2), ('C', 3), ('D', None), ('E', None)] >>> list(zip('ABCDE',range(1,4))) [('A', 1), ('B', 2), ('C', 3)] >>> list(it.zip_longest('ABCDE',range(1,4),[1,2,3,4])) [('A', 1, 1), ('B', 2, 2), ('C', 3, 3), ('D', None, 4), ('E', None, None)] >>>
名字我随便起的,形像就好。看下来如何?十八兵器,样样精通了吗?其实掌握个几样“称手的”即可,何必面面俱到呢 ^_^