Phê bình các câu trả lời khác ở đây:
Không có câu trả lời nào trong số này là các đoạn có kích thước bằng nhau, tất cả đều để lại một đoạn thô sơ ở cuối, vì vậy chúng không hoàn toàn cân bằng. Nếu bạn đang sử dụng các chức năng này để phân phối công việc, bạn đã có triển vọng về một khả năng hoàn thành tốt trước các chức năng khác, vì vậy nó sẽ không làm gì trong khi những người khác tiếp tục làm việc chăm chỉ.
Ví dụ: câu trả lời hàng đầu hiện tại kết thúc bằng:
[60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
[70, 71, 72, 73, 74]]
Tôi chỉ ghét cái runt đó vào cuối!
Những người khác, thích list(grouper(3, xrange(7)))
, và chunk(xrange(7), 3)
cả hai trở về : [(0, 1, 2), (3, 4, 5), (6, None, None)]
. Các None
's chỉ là đệm, và khá thanh nha theo ý kiến của tôi. Họ KHÔNG đồng đều chunk các iterables.
Tại sao chúng ta không thể phân chia những thứ này tốt hơn?
Giải pháp của tôi
Dưới đây là một giải pháp cân bằng, chuyển thể từ một hàm tôi đã sử dụng trong sản xuất (Lưu ý trong Python 3 để thay thế xrange
với 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)
Và tôi đã tạo một trình tạo tương tự nếu bạn đưa nó vào danh sách:
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)]
Và cuối cùng, vì tôi thấy rằng tất cả các hàm trên trả về các phần tử theo thứ tự liền kề (như chúng đã được đưa ra):
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)]
Đầu ra
Để kiểm tra chúng:
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)))
Mà in ra:
[[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]]
Lưu ý rằng trình tạo liền kề cung cấp các khối theo các mẫu có cùng độ dài với hai mẫu kia, nhưng các mục đều theo thứ tự và chúng được chia đều vì người ta có thể chia một danh sách các phần tử rời rạc.