ฉันไม่พบตัวอย่างที่ถูกต้องบนอินเทอร์เน็ตที่ฉันสามารถเห็นความแตกต่างระหว่างตัวอย่างเหล่านี้และสาเหตุที่ต้องเลือกตัวอย่างอื่น
ความแตกต่างระหว่าง chain และ chain.from_iterable ใน itertools คืออะไร?
คำตอบ (6)
ตัวแรกรับอาร์กิวเมนต์ 0 ตัวขึ้นไป โดยแต่ละตัวสามารถวนซ้ำได้ ส่วนตัวที่สองรับหนึ่งอาร์กิวเมนต์ซึ่งคาดว่าจะสร้างค่าวนซ้ำได้:
from itertools import chain
chain(list1, list2, list3)
iterables = [list1, list2, list3]
chain.from_iterable(iterables)
แต่ iterables
สามารถเป็นตัววนซ้ำใด ๆ ที่ให้ผลการวนซ้ำได้:
def gen_iterables():
for i in range(10):
yield range(i)
itertools.chain.from_iterable(gen_iterables())
โดยปกติแล้วการใช้รูปแบบที่สองจะเป็นกรณีของความสะดวก แต่เนื่องจากรูปแบบนี้จะวนซ้ำอินพุตที่ทำซ้ำได้อย่างเกียจคร้าน จึงเป็นวิธีเดียวที่คุณสามารถเชื่อมโยงจำนวนตัววนซ้ำที่มีจำกัด ไม่สิ้นสุด ได้:
def gen_iterables():
while True:
for i in range(5, 10):
yield range(i)
chain.from_iterable(gen_iterables())
ตัวอย่างข้างต้นจะให้ค่าที่สามารถทำซ้ำได้ซึ่งให้รูปแบบวงจรของตัวเลขที่จะไม่มีวันหยุด แต่จะไม่ใช้หน่วยความจำมากเกินกว่าที่ต้องใช้การเรียก range()
เพียงครั้งเดียว
# Return an iterator of iterators
def it_it(): return iter( [iter( [11, 22] ), iter( [33, 44] )] )
print( list(itertools.chain.from_iterable(it_it())) )
print( list(itertools.chain(it_it())) )
print( list(itertools.chain(*it_it())) )
อันแรกดีที่สุด อันที่สองไม่ได้รับที่ตัววนซ้ำที่ซ้อนกัน แต่จะส่งคืนตัววนซ้ำแทนที่จะเป็นตัวเลขที่ต้องการ อันที่สามสร้างเอาต์พุตที่ถูกต้อง แต่มันไม่ได้ขี้เกียจอย่างสมบูรณ์: * บังคับให้สร้างตัววนซ้ำทั้งหมด สำหรับอินพุตใบ้นี้ไม่สำคัญ
- person ToolmakerSteve; 20.12.2013
itertools.chain(*iterables)
- person balki; 15.02.2014
ฉันไม่พบตัวอย่างที่ถูกต้อง ... ซึ่งฉันสามารถเห็นความแตกต่างระหว่างพวกเขา [
chain
และchain.from_iterable
] และเหตุใดจึงเลือกตัวอย่างหนึ่งมากกว่าอีกตัวอย่างหนึ่ง
คำตอบที่ยอมรับนั้นละเอียดถี่ถ้วน สำหรับผู้ที่กำลังมองหาใบสมัครที่รวดเร็ว ลองพิจารณาแยกหลายรายการ:
list(itertools.chain(["a", "b", "c"], ["d", "e"], ["f"]))
# ['a', 'b', 'c', 'd', 'e', 'f']
คุณอาจต้องการใช้รายการเหล่านี้ซ้ำในภายหลัง เพื่อให้รายการสามารถทำซ้ำได้:
iterable = (["a", "b", "c"], ["d", "e"], ["f"])
ความพยายาม
อย่างไรก็ตาม การส่งผ่านแบบทำซ้ำได้ไปที่ chain
จะให้ผลลัพธ์ที่ไม่เรียบ:
list(itertools.chain(iterable))
# [['a', 'b', 'c'], ['d', 'e'], ['f']]
ทำไม คุณผ่าน หนึ่ง รายการ (สิ่งอันดับ) chain
ต้องการแต่ละรายการแยกกัน
โซลูชั่น
เมื่อเป็นไปได้ คุณสามารถแกะไฟล์ที่ทำซ้ำได้:
list(itertools.chain(*iterable))
# ['a', 'b', 'c', 'd', 'e', 'f']
list(itertools.chain(*iter(iterable)))
# ['a', 'b', 'c', 'd', 'e', 'f']
โดยทั่วไป ให้ใช้ .from_iterable
(เนื่องจากใช้ได้กับตัววนซ้ำไม่จำกัด):
list(itertools.chain.from_iterable(iterable))
# ['a', 'b', 'c', 'd', 'e', 'f']
g = itertools.chain.from_iterable(itertools.cycle(iterable))
next(g)
# "a"
พวกเขาทำสิ่งที่คล้ายกันมาก สำหรับ iterable จำนวนเล็กน้อย itertools.chain(*iterables)
และ itertools.chain.from_iterable(iterables)
จะทำงานในลักษณะเดียวกัน
ข้อได้เปรียบที่สำคัญของ from_iterables
อยู่ที่ความสามารถในการจัดการจำนวนการทำซ้ำจำนวนมาก (อาจไม่มีที่สิ้นสุด) เนื่องจากสิ่งเหล่านั้นทั้งหมดไม่จำเป็นต้องพร้อมใช้งานในขณะที่ทำการโทร
*
คลาย iterables
อย่างเกียจคร้านหรือไม่
- person Rotareti; 25.03.2018
itertools.chain(*iterables)
เป็นการเรียกใช้ฟังก์ชัน ข้อโต้แย้งทั้งหมดจะต้องปรากฏ ณ เวลาที่โทร
- person BiGYaN; 27.03.2018
from_iterables
เร็วขึ้น
- person BiGYaN; 30.06.2020
อีกวิธีในการดู:
chain(iterable1, iterable2, iterable3, ...)
ใช้สำหรับเมื่อคุณรู้แล้วว่าคุณมีความสามารถในการวนซ้ำอะไร ดังนั้นคุณจึงสามารถเขียนเป็นอาร์กิวเมนต์ที่คั่นด้วยเครื่องหมายจุลภาคได้
chain.from_iterable(iterable)
ใช้สำหรับเมื่อได้รับ iterable ของคุณ (เช่น iterable1, iterable2, iterable3) มาจาก iterable อื่น
การขยาย @martijn-pieters answer
แม้ว่าการเข้าถึงรายการภายในในการวนซ้ำยังคงเหมือนเดิมและการนำไปปฏิบัติอย่างชาญฉลาด
itertools_chain_from_iterable
(เช่นchain.from_iterable
ใน Python) และchain_new
(เช่นchain
ใน Python)
ในการใช้งาน CPython นั้นเป็นทั้งประเภทเป็ดของ chain_new_internal ก>
มีประโยชน์ในการเพิ่มประสิทธิภาพจากการใช้ chain.from_iterable(x)
หรือไม่ โดยที่ x
สามารถทำซ้ำได้ และจุดประสงค์หลักคือเพื่อใช้รายการสิ่งของที่ราบเรียบในที่สุด
เราสามารถลองเปรียบเทียบด้วย:
import random
from itertools import chain
from functools import wraps
from time import time
from tqdm import tqdm
def timing(f):
@wraps(f)
def wrap(*args, **kw):
ts = time()
result = f(*args, **kw)
te = time()
print('func:%r args:[%r, %r] took: %2.4f sec' % (f.__name__, args, kw, te-ts))
return result
return wrap
def generate_nm(m, n):
# Creates m generators of m integers between range 0 to n.
yield iter(random.sample(range(n), n) for _ in range(m))
def chain_star(x):
# Stores an iterable that will unpack and flatten the list of list.
chain_x = chain(*x)
# Consumes the items in the flatten iterable.
for i in chain_x:
pass
def chain_from_iterable(x):
# Stores an iterable that will unpack and flatten the list of list.
chain_x = chain.from_iterable(x)
# Consumes the items in the flatten iterable.
for i in chain_x:
pass
@timing
def versus(f, n, m):
f(generate_nm(n, m))
P/S: เกณฑ์มาตรฐานกำลังทำงานอยู่... กำลังรอผลลัพธ์
ผลลัพธ์
chain_star, m=1,000, n=1,000
for _ in range(10):
versus(chain_star, 1000, 1000)
[ออก]:
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 1000, 1000), {}] took: 0.6494 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 1000, 1000), {}] took: 0.6603 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 1000, 1000), {}] took: 0.6367 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 1000, 1000), {}] took: 0.6350 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 1000, 1000), {}] took: 0.6296 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 1000, 1000), {}] took: 0.6399 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 1000, 1000), {}] took: 0.6341 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 1000, 1000), {}] took: 0.6381 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 1000, 1000), {}] took: 0.6343 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 1000, 1000), {}] took: 0.6309 sec
chain_from_iterable, m=1,000, n=1,000
for _ in range(10):
versus(chain_from_iterable, 1000, 1000)
[ออก]:
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 1000, 1000), {}] took: 0.6416 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 1000, 1000), {}] took: 0.6315 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 1000, 1000), {}] took: 0.6535 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 1000, 1000), {}] took: 0.6334 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 1000, 1000), {}] took: 0.6327 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 1000, 1000), {}] took: 0.6471 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 1000, 1000), {}] took: 0.6426 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 1000, 1000), {}] took: 0.6287 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 1000, 1000), {}] took: 0.6353 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 1000, 1000), {}] took: 0.6297 sec
chain_star, m=10,000, n=1,000
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 10000, 1000), {}] took: 6.2659 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 10000, 1000), {}] took: 6.2966 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 10000, 1000), {}] took: 6.2953 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 10000, 1000), {}] took: 6.3141 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 10000, 1000), {}] took: 6.2802 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 10000, 1000), {}] took: 6.2799 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 10000, 1000), {}] took: 6.2848 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 10000, 1000), {}] took: 6.3299 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 10000, 1000), {}] took: 6.2730 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 10000, 1000), {}] took: 6.3052 sec
chain_from_iterable, m=10,000, n=1,000
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 10000, 1000), {}] took: 6.3129 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 10000, 1000), {}] took: 6.3064 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 10000, 1000), {}] took: 6.3071 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 10000, 1000), {}] took: 6.2660 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 10000, 1000), {}] took: 6.2837 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 10000, 1000), {}] took: 6.2877 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 10000, 1000), {}] took: 6.2756 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 10000, 1000), {}] took: 6.2939 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 10000, 1000), {}] took: 6.2715 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 10000, 1000), {}] took: 6.2877 sec
chain_star, m=100000, n=1,000
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 100000, 1000), {}] took: 62.7874 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 100000, 1000), {}] took: 63.3744 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 100000, 1000), {}] took: 62.5584 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 100000, 1000), {}] took: 63.3745 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 100000, 1000), {}] took: 62.7982 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 100000, 1000), {}] took: 63.4054 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 100000, 1000), {}] took: 62.6769 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 100000, 1000), {}] took: 62.6476 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 100000, 1000), {}] took: 63.7397 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 100000, 1000), {}] took: 62.8980 sec
chain_from_iterable, m=100000, n=1,000
for _ in range(10):
versus(chain_from_iterable, 100000, 1000)
[ออก]:
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 100000, 1000), {}] took: 62.7227 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 100000, 1000), {}] took: 62.7717 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 100000, 1000), {}] took: 62.7159 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 100000, 1000), {}] took: 62.7569 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 100000, 1000), {}] took: 62.7906 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 100000, 1000), {}] took: 62.6211 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 100000, 1000), {}] took: 62.7294 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 100000, 1000), {}] took: 62.8260 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 100000, 1000), {}] took: 62.8356 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 100000, 1000), {}] took: 62.9738 sec
chain_star, m=500000, n=1,000
for _ in range(3):
versus(chain_from_iterable, 500000, 1000)
[ออก]:
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 500000, 1000), {}] took: 314.5671 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 500000, 1000), {}] took: 313.9270 sec
func:'versus' args:[(<function chain_star at 0x7f5c7188ef28>, 500000, 1000), {}] took: 313.8992 sec
chain_from_iterable, m=500000, n=1,000
for _ in range(3):
versus(chain_from_iterable, 500000, 1000)
[ออก]:
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 500000, 1000), {}] took: 313.8301 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 500000, 1000), {}] took: 313.8104 sec
func:'versus' args:[(<function chain_from_iterable at 0x7f5c7188eb70>, 500000, 1000), {}] took: 313.9440 sec
วิธีดูอีกวิธีหนึ่งคือใช้ chain.from_iterable
เมื่อคุณมีการทำซ้ำได้เช่นการวนซ้ำแบบซ้อน (หรือแบบผสม iterbale) และใช้ลูกโซ่สำหรับการวนซ้ำแบบง่าย