คำติชมของคำตอบอื่น ๆ ที่นี่:
ไม่มีคำตอบเหล่านี้เป็นชิ้นขนาดเท่ากันพวกเขาทั้งหมดออกจากชิ้น runt ตอนท้ายดังนั้นพวกเขาไม่สมดุลอย่างสมบูรณ์ หากคุณใช้ฟังก์ชั่นเหล่านี้เพื่อแจกจ่ายงานคุณได้สร้างโอกาสที่จะทำให้งานเสร็จก่อนที่คนอื่นจะสร้างมันขึ้นมาดังนั้นมันจะไม่ทำอะไรเลยในขณะที่คนอื่นทำงานหนักต่อไป
ตัวอย่างเช่นคำตอบยอดนิยมปัจจุบันลงท้ายด้วย:
[60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
[70, 71, 72, 73, 74]]
ฉันแค่เกลียดแค้นที่ท้าย!
คนอื่น ๆ ชอบlist(grouper(3, xrange(7)))
และchunk(xrange(7), 3)
ทั้งสองกลับมา: [(0, 1, 2), (3, 4, 5), (6, None, None)]
. None
's เป็นเพียงรองและค่อนข้างไม่งดงามในความคิดของฉัน พวกเขาจะไม่ chunking iterables อย่างสม่ำเสมอ
ทำไมเราไม่หารเหล่านี้ให้ดีกว่านี้?
โซลูชันของฉัน
นี่คือวิธีการแก้ปัญหาที่สมดุลซึ่งดัดแปลงมาจากฟังก์ชั่นที่ฉันใช้ในการผลิต (หมายเหตุใน Python 3 เพื่อแทนที่xrange
ด้วยrange
):
def baskets_from(items, maxbaskets=25):
baskets = [[] for _ in xrange(maxbaskets)] # in Python 3 use range
for i, item in enumerate(items):
baskets[i % maxbaskets].append(item)
return filter(None, baskets)
และฉันสร้างเครื่องกำเนิดไฟฟ้าที่ทำเช่นเดียวกันหากคุณใส่ไว้ในรายการ:
def iter_baskets_from(items, maxbaskets=3):
'''generates evenly balanced baskets from indexable iterable'''
item_count = len(items)
baskets = min(item_count, maxbaskets)
for x_i in xrange(baskets):
yield [items[y_i] for y_i in xrange(x_i, item_count, baskets)]
และในที่สุดเนื่องจากฉันเห็นว่าฟังก์ชั่นทั้งหมดข้างต้นคืนองค์ประกอบตามลำดับที่ต่อเนื่องกัน (ตามที่ได้รับ):
def iter_baskets_contiguous(items, maxbaskets=3, item_count=None):
'''
generates balanced baskets from iterable, contiguous contents
provide item_count if providing a iterator that doesn't support len()
'''
item_count = item_count or len(items)
baskets = min(item_count, maxbaskets)
items = iter(items)
floor = item_count // baskets
ceiling = floor + 1
stepdown = item_count % baskets
for x_i in xrange(baskets):
length = ceiling if x_i < stepdown else floor
yield [items.next() for _ in xrange(length)]
เอาท์พุต
เพื่อทดสอบพวกเขา
print(baskets_from(xrange(6), 8))
print(list(iter_baskets_from(xrange(6), 8)))
print(list(iter_baskets_contiguous(xrange(6), 8)))
print(baskets_from(xrange(22), 8))
print(list(iter_baskets_from(xrange(22), 8)))
print(list(iter_baskets_contiguous(xrange(22), 8)))
print(baskets_from('ABCDEFG', 3))
print(list(iter_baskets_from('ABCDEFG', 3)))
print(list(iter_baskets_contiguous('ABCDEFG', 3)))
print(baskets_from(xrange(26), 5))
print(list(iter_baskets_from(xrange(26), 5)))
print(list(iter_baskets_contiguous(xrange(26), 5)))
ซึ่งพิมพ์ออกมา:
[[0], [1], [2], [3], [4], [5]]
[[0], [1], [2], [3], [4], [5]]
[[0], [1], [2], [3], [4], [5]]
[[0, 8, 16], [1, 9, 17], [2, 10, 18], [3, 11, 19], [4, 12, 20], [5, 13, 21], [6, 14], [7, 15]]
[[0, 8, 16], [1, 9, 17], [2, 10, 18], [3, 11, 19], [4, 12, 20], [5, 13, 21], [6, 14], [7, 15]]
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [12, 13, 14], [15, 16, 17], [18, 19], [20, 21]]
[['A', 'D', 'G'], ['B', 'E'], ['C', 'F']]
[['A', 'D', 'G'], ['B', 'E'], ['C', 'F']]
[['A', 'B', 'C'], ['D', 'E'], ['F', 'G']]
[[0, 5, 10, 15, 20, 25], [1, 6, 11, 16, 21], [2, 7, 12, 17, 22], [3, 8, 13, 18, 23], [4, 9, 14, 19, 24]]
[[0, 5, 10, 15, 20, 25], [1, 6, 11, 16, 21], [2, 7, 12, 17, 22], [3, 8, 13, 18, 23], [4, 9, 14, 19, 24]]
[[0, 1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15], [16, 17, 18, 19, 20], [21, 22, 23, 24, 25]]
โปรดสังเกตว่าตัวกำเนิดที่ต่อเนื่องกันจัดให้ชิ้นส่วนในรูปแบบความยาวเดียวกันกับอีกสองชิ้น แต่รายการทั้งหมดนั้นอยู่ในลำดับและพวกมันจะถูกแบ่งเท่า ๆ กันอย่างที่ใครคนหนึ่งอาจแบ่งรายการองค์ประกอบที่ไม่ต่อเนื่องกัน