算法:用itertools.product()简化嵌套for循环
今天这一题叫做“偷瞄到的密码”:
警察跟踪一名窃贼来到了一个仓库门前。仓库的密码锁盘如下:
1 2 3
4 5 6
7 8 9
0
窃贼输入密码后进了门。警察“觉得”自己看到了密码比如1357,但是也有可能是相邻的数字(相邻仅包括正上下左右,不包括对角线),比如第一位不是1,而是相邻的4和2(不包括5)。
可能的密码是哪些组合呢?
这道题目可以抽象成:
1. 0-9各自都对应了一组相邻数字
现给定一个数字串:
2. 对数字串中的每个数字,找到对应的相邻数组
3. 计算从这些相邻组中各挑一个形成的所有可能组合并输出
实现要点:
1. 上述#3实际上是一个嵌套的多重for循环:
for 数字串中的每个数字:
for 该数字相邻数组中的每个数字:
用itertools模块的product方法可以将这个过程简化为一步完成。根据Python手册,product(A, B)的结果是((x,y) for x in A for y in B)。
2. 对于函数或者方法如product(A, B, C, D),如果ABCD在一个列表里ls=[A, B, C, D],如何把ls传给product?
用*,即product(*ls)。
3. product的输出为元组。用join合并元组的所有元素,以字符串的形式输出密码组合。
Python实现:
1 #-*- coding:utf-8 -*- 2 __author__ = 'Administrator' 3 4 from itertools import product 5 import time 6 7 combine=["08","124","1235","236","1457","24568","3569","478", 8 "57890","689"] 9 10 def get_pin(observe): 11 return ["".join(p) for p in product(*(combine[int(d)] for d in observe))] 12 13 def get_pin2(observe): 14 comb=[] 15 li=[] 16 for d in observe: 17 comb.append(combine[int(d)]) 18 for p in product(*comb): 19 li.append("".join(p)) 20 return li 21 22 if __name__=="__main__": 23 t0=time.time() 24 for i in range(10000): 25 get_pin("1357") 26 t1=time.time()-t0 27 print(t1) 28 print("-"*100) 29 t0=time.time() 30 for i in range(10000): 31 get_pin2("1357") 32 t1=time.time()-t0 33 print(t1)
输出时间对比:
0.6550376415252686
----------------------------------------------------------------------------------------------------
0.7860448360443115