目录
一、简介
该模块标准化了一套快速的,内存高效的工具的核心集,这些工具本身或结合使用很有用。它们共同构成了一个“迭代器代数”,从而可以在纯Python中简洁高效地构建专用工具。
二、常用方法介绍
2.1.获取嵌套循环结果product()
输入可迭代项的笛卡尔积
大致等效于生成器表达式中的嵌套for循环。例如, 返回与相同的结果。product(A, B)((x,y) for x in A for y in B)
嵌套循环就像里程表一样循环,最右边的元素在每次迭代中都前进。此模式创建字典顺序,以便如果对输入的可迭代对象进行排序,则将按排序顺序发出产品元组。
itertools.product(* iterables,repeat = 1 )
举例:
product('ABCD', repeat=2)
#AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD
等效代码:
此函数大致等效于以下代码,不同之处在于实际实现不会在内存中建立中间结果:
def product(*args, repeat=1):
# product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
# product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
pools = [tuple(pool) for pool in args] * repeat
result = [[]]
for pool in pools:
result = [x+[y] for x in result for y in pool]
for prod in result:
yield tuple(prod)
2.2.获取指定长度的全排列方法permutations()
返回iterable中元素的连续r长度排列。
itertools.permutations(iterable, r=None)
举例:
permutations('ABCD', 2)
#AB AC AD BA BC BD CA CB CD DA DB DC
内部代码实现
def permutations(iterable, r=None):
# permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC
# permutations(range(3)) --> 012 021 102 120 201 210
pool = tuple(iterable)
n = len(pool)
r = n if r is None else r
if r > n:
return
indices = list(range(n))
cycles = list(range(n, n-r, -1))
yield tuple(pool[i] for i in indices[:r])
while n:
for i in reversed(range(r)):
cycles[i] -= 1
if cycles[i] == 0:
indices[i:] = indices[i+1:] + indices[i:i+1]
cycles[i] = n - i
else:
j = cycles[i]
indices[i], indices[-j] = indices[-j], indices[i]
yield tuple(pool[i] for i in indices[:r])
break
else:
return
2.3.按排序顺序,没有重复的元素combinations()
itertools.combinations(iterable, r)
r长度元组,按排序顺序,没有重复的元素
举例:
combinations('ABCD', 2)
#AB AC AD BC BD CD
根据输入iterable的顺序,按字典顺序发出组合元组。因此,如果对输入的iterable进行排序,则将按排序顺序生成组合元组。
元素根据其位置而不是其价值被视为唯一。因此,如果输入元素是唯一的,则每个组合中都不会有重复值。
相当于
def combinations(iterable, r):
# combinations('ABCD', 2) --> AB AC AD BC BD CD
# combinations(range(4), 3) --> 012 013 023 123
pool = tuple(iterable)
n = len(pool)
if r > n:
return
indices = list(range(r))
yield tuple(pool[i] for i in indices)
while True:
for i in reversed(range(r)):
if indices[i] != i + n - r:
break
else:
return
indices[i] += 1
for j in range(i+1, r):
indices[j] = indices[j-1] + 1
yield tuple(pool[i] for i in indices)
的代码combinations()还可以表示为permutations()元素过滤后的子序列,其中元素未按顺序排列(根据它们在输入池中的位置):
def combinations(iterable, r):
pool = tuple(iterable)
n = len(pool)
for indices in permutations(range(n), r):
if sorted(indices) == list(indices):
yield tuple(pool[i] for i in indices)
2.4.按排序顺序,有重复的元素combinations_with_replacement()
输入可迭代返回元素的r长度子序列, 允许单个元素重复多次。
itertools.combinations_with_replacement(iterable, r)
举例:
combinations_with_replacement('ABCD', 2)
#AA AB AC AD BB BC BD CC CD DD
根据输入iterable的顺序,按字典顺序发出组合元组。因此,如果对输入的iterable进行排序,则将按排序顺序生成组合元组。
元素根据其位置而不是其价值被视为唯一。因此,如果输入元素是唯一的,则生成的组合也将是唯一的。
大致相当于:
def combinations_with_replacement(iterable, r):
# combinations_with_replacement('ABC', 2) --> AA AB AC BB BC CC
pool = tuple(iterable)
n = len(pool)
if not n and r:
return
indices = [0] * r
yield tuple(pool[i] for i in indices)
while True:
for i in reversed(range(r)):
if indices[i] != n - 1:
break
else:
return
indices[i:] = [indices[i] + 1] * (r - i)
yield tuple(pool[i] for i in indices)
的代码combinations_with_replacement()还可以表示为product()元素过滤后的子序列,其中元素未按顺序排列(根据它们在输入池中的位置):
def combinations_with_replacement(iterable, r):
pool = tuple(iterable)
n = len(pool)
for indices in product(range(n), repeat=r):
if sorted(indices) == list(indices):
yield tuple(pool[i] for i in indices)
返回的项目的数量时。(n+r-1)! / r! / (n-1)!n > 0
三、应用-24点游戏算法:
问题描述:给出4个1-10的数字,通过加减乘除,得到数字为24就算胜利
import sys
import itertools
def func(cards):
for nums in itertools.permutations(cards): # 四个数
for ops in itertools.product('+-*/', repeat=3): # 三个运算符(可重复!)
# 构造三种中缀表达式 (bsd)
bds1 = '({0}{4}{1}){5}({2}{6}{3})'.format(*nums, *ops) # (a+b)*(c-d)
bds2 = '(({0}{4}{1}){5}{2}){6}{3}'.format(*nums, *ops) # (a+b)*c-d
bds3 = '{0}{4}({1}{5}({2}{6}{3}))'.format(*nums, *ops) # a/(b-(c/d))
for bds in [bds1, bds2, bds3]: # 遍历
try:
if abs(eval(bds) - 24.0) < 1e-10: # eval函数
return 'true'
except ZeroDivisionError: # 零除错误!
continue
return 'false'
for line in sys.stdin:
nums = list(map(int, line.strip().split()))
print(str(func(nums)).lower())