s = [1,2,3,4,5,6,7,8,9]
n = 3
zip(*[iter(s)]*n) # returns [(1,2,3),(4,5,6),(7,8,9)]
วิธีการzip(*[iter(s)]*n)
ทำงานหรือไม่ จะเป็นอย่างไรหากเขียนด้วยรหัสแบบละเอียดมากกว่านี้
s = [1,2,3,4,5,6,7,8,9]
n = 3
zip(*[iter(s)]*n) # returns [(1,2,3),(4,5,6),(7,8,9)]
วิธีการzip(*[iter(s)]*n)
ทำงานหรือไม่ จะเป็นอย่างไรหากเขียนด้วยรหัสแบบละเอียดมากกว่านี้
คำตอบ:
iter()
เป็นตัววนซ้ำตามลำดับ [x] * n
ผลิตรายการที่มีn
ปริมาณของx
คือรายการความยาวที่แต่ละองค์ประกอบn
แยกลำดับเป็นอาร์กิวเมนต์สำหรับการเรียกใช้ฟังก์ชัน ดังนั้นคุณจะส่งตัววนซ้ำเดิม 3 ครั้งไปและมันจะดึงรายการจากตัววนซ้ำทุกครั้งx
*arg
zip()
x = iter([1,2,3,4,5,6,7,8,9])
print zip(x, x, x)
yield
s (= return
s) รายการคุณสามารถจินตนาการว่ารายการนี้ "ใช้ไปแล้ว" ดังนั้นในครั้งต่อไปที่มีการเรียกตัววนซ้ำระบบจะให้รายการ "ไม่บริโภค" ถัดไป
คำตอบที่ดีอื่น ๆ และแสดงความคิดเห็นกันอธิบายบทบาทของการโต้แย้งการเปิดออกและซิป ()
ดังที่Ignacioและujukatzelกล่าวคุณจะส่งต่อzip()
การอ้างอิงสามรายการไปยังตัววนซ้ำเดียวกันและzip()
สร้าง 3 tuples ของจำนวนเต็มตามลำดับ - จากการอ้างอิงแต่ละรายการไปยัง iterator:
1,2,3,4,5,6,7,8,9 1,2,3,4,5,6,7,8,9 1,2,3,4,5,6,7,8,9
^ ^ ^
^ ^ ^
^ ^ ^
และเนื่องจากคุณขอตัวอย่างโค้ด verbose เพิ่มเติม:
chunk_size = 3
L = [1,2,3,4,5,6,7,8,9]
# iterate over L in steps of 3
for start in range(0,len(L),chunk_size): # xrange() in 2.x; range() in 3.x
end = start + chunk_size
print L[start:end] # three-item chunks
ปฏิบัติตามค่าของstart
และend
:
[0:3) #[1,2,3]
[3:6) #[4,5,6]
[6:9) #[7,8,9]
FWIW คุณจะได้ผลลัพธ์เดียวกันmap()
ด้วยอาร์กิวเมนต์เริ่มต้นของNone
:
>>> map(None,*[iter(s)]*3)
[(1, 2, 3), (4, 5, 6), (7, 8, 9)]
สำหรับข้อมูลเพิ่มเติมzip()
และmap()
: http://muffinresearch.co.uk/archives/2007/10/16/python-transposing-lists-with-map-and-zip/
ฉันคิดว่าสิ่งหนึ่งที่พลาดไปในคำตอบทั้งหมด (อาจชัดเจนสำหรับผู้ที่คุ้นเคยกับการย้ำซ้ำ) แต่คนอื่นไม่ชัดเจนนักคือ -
เนื่องจากเรามีตัววนซ้ำเหมือนกันมันจึงถูกใช้ไปและองค์ประกอบที่เหลือจะถูกใช้โดย zip ดังนั้นถ้าเราใช้แค่รายการไม่ใช่ iter เช่น
l = range(9)
zip(*([l]*3)) # note: not an iter here, the lists are not emptied as we iterate
# output
[(0, 0, 0), (1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5), (6, 6, 6), (7, 7, 7), (8, 8, 8)]
การใช้ตัววนซ้ำจะแสดงค่าและเก็บเฉพาะที่เหลืออยู่ดังนั้นสำหรับ zip เมื่อใช้ 0 1 แล้วจะพร้อมใช้งาน 2 และอื่น ๆ เป็นสิ่งที่บอบบาง แต่ค่อนข้างฉลาด !!!
iter(s)
ส่งคืนตัววนซ้ำสำหรับ s
[iter(s)]*n
สร้างรายการ n คูณตัววนซ้ำเดียวกันสำหรับ s
ดังนั้นเมื่อทำzip(*[iter(s)]*n)
มันจะแยกรายการจากตัวทำซ้ำทั้งสามรายการจากรายการตามลำดับ เนื่องจากตัววนซ้ำทั้งหมดเป็นวัตถุเดียวกันจึงจัดกลุ่มรายการเป็นชิ้น ๆn
เท่านั้น
คำแนะนำหนึ่งคำสำหรับการใช้ zip ด้วยวิธีนี้ มันจะตัดรายการของคุณถ้าความยาวหารเท่ากันไม่ได้ ในการแก้ไขปัญหานี้คุณสามารถใช้itertools.izip_longestถ้าคุณสามารถยอมรับค่าการเติม หรือคุณสามารถใช้สิ่งนี้:
def n_split(iterable, n):
num_extra = len(iterable) % n
zipped = zip(*[iter(iterable)] * n)
return zipped if not num_extra else zipped + [iterable[-num_extra:], ]
การใช้งาน:
for ints in n_split(range(1,12), 3):
print ', '.join([str(i) for i in ints])
พิมพ์:
1, 2, 3
4, 5, 6
7, 8, 9
10, 11
itertools
สูตร: docs.python.org/2/library/itertools.html#recipes grouper
ไม่จำเป็นต้องสร้างล้อใหม่
มันอาจจะง่ายกว่าที่จะเห็นว่าเกิดอะไรขึ้นในล่าม python หรือipython
ด้วยn = 2
:
In [35]: [iter("ABCDEFGH")]*2
Out[35]: [<iterator at 0x6be4128>, <iterator at 0x6be4128>]
ดังนั้นเราจึงมีรายการตัวทำซ้ำสองรายการซึ่งชี้ไปที่วัตถุตัววนซ้ำเดียวกัน โปรดจำไว้ว่าiter
บนวัตถุส่งคืนอ็อบเจ็กต์ตัววนซ้ำและในสถานการณ์นี้มันเป็นตัววนซ้ำสองครั้งเนื่องจาก*2
น้ำตาลวากยสัมพันธ์ของไพ ธ อน ตัวทำซ้ำยังทำงานเพียงครั้งเดียว
นอกจากนี้ให้zip
ใช้จำนวนการวนซ้ำจำนวนเท่าใดก็ได้ ( ลำดับคือการวนซ้ำ ) และสร้างทูเปิลจากองค์ประกอบ i ของแต่ละลำดับอินพุต เนื่องจากตัววนซ้ำทั้งสองเหมือนกันในกรณีของเรา zip จึงย้ายตัววนซ้ำเดียวกันสองครั้งสำหรับทูเพิล 2 องค์ประกอบแต่ละรายการ
In [41]: help(zip)
Help on built-in function zip in module __builtin__:
zip(...)
zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)]
Return a list of tuples, where each tuple contains the i-th element
from each of the argument sequences. The returned list is truncated
in length to the length of the shortest argument sequence.
ตัวดำเนินการunpacking ( *
)ช่วยให้มั่นใจได้ว่าตัววนซ้ำทำงานจนหมดซึ่งในกรณีนี้ก็คือจนกว่าจะไม่มีอินพุตเพียงพอที่จะสร้างทูเพิล 2 องค์ประกอบ
สิ่งนี้สามารถขยายเป็นมูลค่าn
และใช้zip(*[iter(s)]*n)
งานได้ตามที่อธิบายไว้
*
เป็นเพียงความสะดวกในการทำซ้ำวัตถุ ลองใช้ด้วยสเกลาร์และรายการ ลองprint(*zip(*[iter("ABCDEFG")]*2))
เทียบกับprint(*zip(*[iter("ABCDEFG"), iter("ABCDEFG")]))
. จากนั้นเริ่มแยกทั้งสองออกเป็นขั้นตอนเล็ก ๆ เพื่อดูว่าวัตถุตัววนซ้ำที่แท้จริงในสองคำสั่งคืออะไร