itertools
เวลาใช้จึงต้องเรียกใช้import
เข้ามาก่อนเลยimport itertools
map
, filter
และ reversed
ซึ่งได้กล่าวถึงไปแล้ว และในบทนี้จะแนะนำเพิ่มอีก ๒ ตัว คือ zip
และ enumerate
print(list(enumerate('กขคงจ'))) # ได้ [(0, 'ก'), (1, 'ข'), (2, 'ค'), (3, 'ง'), (4, 'จ')]
enumerate
นั้นเป็นอิเทอเรเตอร์ดังนั้นต้องใช้ list
เพื่อแปลงเป็นลิสต์อีกทีเพื่อแสดงสมาชิกทั้งหมดstart
จะกำหนดจุดเริ่มต้นของการนับได้ ถ้าไม่ใส่จะเริ่มจาก 0
print(list(enumerate('OBAFGKM',start=100))) # ได้ [(100, 'O'), (101, 'B'), (102, 'A'), (103, 'F'), (104, 'G'), (105, 'K'), (106, 'M')]
enumerate
มีประโยชน์เวลาที่เราต้องการให้เวลาที่ใช้ for
เพื่อวนซ้ำอยู่มีตัวเลขบางอย่างที่ช่วยนับจำนวนรอบ เวลาใช้ for
สามารถนำตัวแปรมารับ ๒ ตัวได้ โดยตัวแรกจะรับค่าตัวเลข และตัวหลังจะรับสมาชิกของข้อมูล
for i,e in enumerate(['H','He','Li','Be','B'],start=1):
print('%d:%s'%(i,e),end=', ')
# ได้ 1:H, 2:He, 3:Li, 4:Be, 5:B,
def genenumerate(ชุดข้อมูล,start=0):
i = start
for c in ชุดข้อมูล:
yield (i,c)
i += 1
print(list(zip('กขค','abc'))) # ได้ [('ก', 'a'), ('ข', 'b'), ('ค', 'c')]
for
ตั้งแต่ ๒ ลิสต์ขึ้นไป
a = ['ไก่','จิก','เด็ก','ตาย','เด็ก','ตาย','บน','ปาก','โอ่ง']
b = 'กจฎฏดตบปอ'
for x,y in zip(a,b):
print(y+':'+x, end='|')
# ได้ ก:ไก่|จ:จิก|ฎ:เด็ก|ฏ:ตาย|ด:เด็ก|ต:ตาย|บ:บน|ป:ปาก|อ:โอ่ง|
print(dict(zip(b,a))) # ได้ {'จ': 'จิก', 'อ': 'โอ่ง', 'ต': 'ตาย', 'ฏ': 'ตาย', 'ด': 'เด็ก', 'ฎ': 'เด็ก', 'ป': 'ปาก', 'ก': 'ไก่', 'บ': 'บน'}
enumerate
ขึ้นมาดูได้
def genzip(*กลุ่มชุดข้อมูล):
s = tuple(map(iter,กลุ่มชุดข้อมูล))
while(1):
y = tuple(map(next,s))
if(len(y)<len(s)): break
yield y
zip
จะคืนค่าเป็นลิสต์ไม่ใช่อิเทอเรเตอร์ ดังนั้นไม่ต้องมาแปลงเป็นลิสต์อีกทีเพื่อแสดงผลfor i in itertools.count(10,10):
if(i>=100): break
print(i,end='.')
# ได้ 10.20.30.40.50.60.70.80.90.
0
และไล่ไปทีละ 1
def count(เริ่มต้น=0,ระยะห่าง=1):
n = เริ่มต้น
while(1):
yield n
n += ระยะห่าง
cyc = itertools.cycle(range(2,7,2))
i = 0
while(i<30):
print(next(cyc),end=';')
i += 1
# ได้ 2;4;6;2;4;6;2;4;6;2;4;6;2;4;6;2;4;6;2;4;6;2;4;6;2;4;6;2;4;6;
def cycle(ชุดข้อมูล):
s = tuple(ชุดข้อมูล)
while(1):
for x in s:
yield x
print([list(itertools.repeat('o',7))]) # ได้ [['o', 'o', 'o', 'o', 'o', 'o', 'o']]
def repeat(ออบเจ็กต์,จำนวนครั้ง='อนันต์'):
if(จำนวนครั้ง != 'อนันต์'): # กรณีที่ใส่จำนวนครั้ง
for i in range(จำนวนครั้ง):
yield ออบเจ็กต์
else: # กรณีที่ไม่ใส่จำนวนครั้ง ให้วนอนันต์ครั้ง
while(1):
yield ออบเจ็กต์
print(list(itertools.chain([1,2],range(3,7),(7,8),{9,10}))) # ได้ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def chain(*ชุดข้อมูลทั้งหมด):
for ชุดข้อมูลแต่ละชุด in ชุดข้อมูลทั้งหมด:
for ข้อมูลในชุด in ชุดข้อมูลแต่ละชุด:
yield ข้อมูลในชุด
x = ['x=1','x=2','x=3']
y = ['y=1','y=2']
print(list(itertools.product(x,y))) # [('x=1', 'y=1'), ('x=1', 'y=2'), ('x=2', 'y=1'), ('x=2', 'y=2'), ('x=3', 'y=1'), ('x=3', 'y=2')]
print(len(list(itertools.product(range(7),range(6),range(2))))) # ได้ 84
repeat
ซึ่งใช้ระบุว่าต้องการให้ข้อมูลชุดหนึ่งถูกหยิบมาแจกแจงซ้ำกี่ครั้ง ถ้าไม่ใส่จะมีค่าเป็น 1
หมายความว่าข้อมูลแต่ละชุดถูกหยิบมาครั้งเดียว
print(list(itertools.product('+-',repeat=3))) # ได้ [('+', '+', '+'), ('+', '+', '-'), ('+', '-', '+'), ('+', '-', '-'), ('-', '+', '+'), ('-', '+', '-'), ('-', '-', '+'), ('-', '-', '-')]
print(len(list(itertools.product('+-',repeat=10)))) # ได้ 1024
print(' + '.join(map(''.join,itertools.product('xyz',repeat=3)))) # ได้ yzz + zxx + zxy + zxz + zyx + zyy + zyz + zzx + zzy + zzz
for
๒ ชั้น
def product2(ชุดข้อมูล1,ชุดข้อมูล2):
s1 = tuple(ชุดข้อมูล1)
s2 = tuple(ชุดข้อมูล2)
for c1 in s1:
for c2 in s2:
yield (c1,c2)
for
ซ้อนกัน ๓ ชั้น แต่ปัญหาคือเราต้องทำให้รองรับได้หมดไม่ว่าจะมีข้อมูลกี่ชุดdef productn(*กลุ่มชุดข้อมูล):
s = tuple(map(tuple,กลุ่มชุดข้อมูล))
if(len(s)==2):
for c1 in s[0]:
for c2 in s[1]:
yield (c1,c2)
else:
for c1 in productn(*s[:-1]): # เรียกใช้ตัวเอง
for c2 in s[-1]:
yield c1 + (c2,)
repeat
เข้าไปด้วย สุดท้ายแล้วก็เลยเขียนเป็นแบบนี้
def product(*กลุ่มชุดข้อมูล,repeat=1):
s = tuple(map(tuple,กลุ่มชุดข้อมูล))*repeat
if(len(s)==2):
for c1 in s[0]:
for c2 in s[1]:
yield (c1,c2)
else:
for c1 in product(*s[:-1]):
for c2 in s[-1]:
yield c1 + (c2,)
print(list(itertools.permutations('xy'))) # ได้ [('x', 'y'), ('y', 'x')]
print(' + '.join(map(''.join,itertools.permutations('xyz')))) # ได้ xyz + xzy + yxz + yzx + zxy + zyx
print(' + '.join(map(''.join,itertools.permutations(['x','y','z'],2)))) # ได้ xy + xz + yx + yz + zx + zy
itertools.product
ให้เป็นประโยชน์ได้ โดยเอาชุดข้อมูลที่ป้อนเข้ามาเพียงอันเดียวนี้มาแจกแจงตามจำนวนที่ต้องการ เลือกด้วยคีย์เวิร์ด repeat
set
ช่วยได้ เพราะเซ็ตมีคุณสมบัติที่ว่าสมาชิกห้ามซ้ำ หากตรวจสอบความยาวหลังแปลงเป็นเซ็ตแล้วพบว่าลดลงก็แสดงว่ามีตัวซ้ำ ก็ตัดกรณีนั้นทิ้ง
def permutations(ชุดข้อมูล,r='จำนวนข้อมูลทั้งหมด'):
s = tuple(ชุดข้อมูล)
n = len(s)
if(r=='จำนวนข้อมูลทั้งหมด'): r = len(n)
for ii in product(range(n),repeat=r):
if(len(set(ii)) == len(ii)):
yield tuple(s[i] for i in ii)
combinations
ต่างจาก permutations
ตรงที่ไม่สนใจลำดับของการหยิบ ดังนั้นผลที่ได้จะมีจำนวนน้อยกว่า โดยตัดตัวที่มีสมาชิกซ้ำกันออกไปpermutations
แต่อาร์กิวเมนต์ตัวหลังคือจำนวนที่เลือกนั้นจำเป็นต้องใส่ จะละไว้ไม่ได้
print(list(itertools.combinations('xyzt',4))) # ได้ [('x', 'y', 'z', 't')]
print(' '.join(map(''.join,itertools.combinations('xyzt',3)))) # ได้ xyz xyt xzt yzt
print(' '.join(map(''.join,itertools.combinations(['x','y','z','t'],2)))) # ได้ xy xz xt yz yt zt
permutations
แต่เพิ่มเงื่อนไขว่าจะต้องมีการจัดเรียงรูปแบบเดียว คือตามลำดับเดิมที่ถูกจัดวางในกลุ่ม ดังนั้นหมายความว่าหากใช้ฟังก์ชัน sorted
เพื่อจัดเรียงแล้วจะต้องได้เท่าเดิม ตัวที่ไม่เหมือนเดิมแสดงว่าเรียงลำดับไม่ถูกต้องอยู่ก็คัดออกไป
def combinations(ชุดข้อมูล,r):
s = tuple(ชุดข้อมูล)
n = len(s)
for ii in product(range(n),repeat=r):
if(sorted(ii) == list(ii) and len(set(ii)) == len(ii)):
yield tuple(s[i] for i in ii)
combinations
แต่ว่าพิจารณาในกรณีที่สามารถเลือกซ้ำได้product
, permutations
, combinations
และ combinations_with_replacement
ดูได้
print(list(itertools.product('กขค',repeat=2))) # ได้ [('ก', 'ก'), ('ก', 'ข'), ('ก', 'ค'), ('ข', 'ก'), ('ข', 'ข'), ('ข', 'ค'), ('ค', 'ก'), ('ค', 'ข'), ('ค', 'ค')]
print(list(itertools.permutations('กขค',2))) # ได้ [('ก', 'ข'), ('ก', 'ค'), ('ข', 'ก'), ('ข', 'ค'), ('ค', 'ก'), ('ค', 'ข')]
print(list(itertools.combinations('กขค',2))) # ได้ [('ก', 'ข'), ('ก', 'ค'), ('ข', 'ค')]
print(list(itertools.combinations_with_replacement(' กขค',2))) # ได้ [('ก', 'ก'), ('ก', 'ข'), ('ก', 'ค'), ('ข', 'ข'), ('ข', 'ค'), ('ค', 'ค')]
combinations
แต่ตัดเงื่อนไขที่ว่าต้องไม่เลือกซ้ำทิ้งไป
def combinations_with_replacement(ชุดข้อมูล,r):
s = tuple(ชุดข้อมูล)
n = len(s)
for ii in product(range(n),repeat=r):
if(sorted(ii) == list(ii)):
yield tuple(s[i] for i in ii)
ติดตามอัปเดตของบล็อกได้ที่แฟนเพจ