2010-09-19 58 views
7

Tôi muốn để có thể tham gia một chuỗi như:Đây có phải là cách bạn phân trang hoặc có thuật toán tốt hơn không?

my_sequence = ['foo', 'bar', 'baz', 'spam', 'eggs', 'cheese', 'yogurt'] 

Sử dụng một chức năng như:

my_paginated_sequence = get_rows(my_sequence, 3) 

Để nhận được:

[['foo', 'bar', 'baz'], ['spam', 'eggs', 'cheese'], ['yogurt']] 

Đây là những gì tôi đã đưa ra bằng chỉ cần suy nghĩ qua nó:

def get_rows(sequence, num): 
    count = 1 
    rows = list() 
    cols = list() 
    for item in sequence: 
     if count == num: 
      cols.append(item) 
      rows.append(cols) 
      cols = list() 
      count = 1 
     else: 
      cols.append(item) 
      count += 1 
    if count > 0: 
     rows.append(cols) 
    return rows 
+2

@Noon - thx, không nghĩ thêm điều đó. Ngoài ra, bạn có phải là một ninja tình cờ? – orokusaki

+0

có thể trùng lặp của [Lợi nhuận nhiều đối tượng tại một thời điểm từ một đối tượng có thể lặp lại?] (Http://stackoverflow.com/questions/2202461/yield-multiple-objects-at-a-time-from-an-iterable-object) –

+0

có thể trùng lặp của [Làm thế nào để bạn chia danh sách thành các khối có kích thước đồng đều trong Python?] (Http://stackoverflow.com/q/312443/54262) –

Trả lời

11

Nếu bạn biết bạn có một chuỗi sliceable (danh sách hoặc tuple),

def getrows_byslice(seq, rowlen): 
    for start in xrange(0, len(seq), rowlen): 
     yield seq[start:start+rowlen] 

Điều này tất nhiên là một máy phát điện, vì vậy nếu bạn hoàn toàn cần một danh sách như là kết quả, bạn sẽ sử dụng list(getrows_byslice(seq, 3)) hoặc tương tự, tất nhiên.

Nếu bạn bắt đầu với một iterable chung, các itertools recipes lời đề nghị giúp đỡ với grouper thức ...:

import itertools 

def grouper(n, iterable, fillvalue=None): 
    "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx" 
    args = [iter(iterable)] * n 
    return itertools.izip_longest(fillvalue=fillvalue, *args) 

(một lần nữa, bạn sẽ cần phải gọi list về vấn đề này nếu một danh sách là những gì bạn muốn, tất nhiên).

Vì bạn thực sự muốn tuple cuối cùng bị cắt bớt thay vì được lấp đầy, bạn sẽ cần phải "cắt" các giá trị điền sau đó từ bộ cuối cùng.

+0

xem ý tôi là gì về Jedi. Tôi cảm thấy như tôi sẽ không bao giờ có thể làm những thứ như thế ngay từ đầu tôi. Bạn có bao giờ cảm thấy như vậy trở lại trong ngày? – orokusaki

+0

@orokusaki, tất nhiên - nhưng sau đó tôi bắt đầu đọc các tài liệu (hãy nhớ rằng chức năng 'cá mú 'được trích dẫn ngay từ các tài liệu! -). –

+1

Ngoài ra, tôi đang nói chuyện với anh trai tôi trên điện thoại về sự hữu ích của bạn đối với cộng đồng Python nói chung. Cả hai chúng tôi đều tự hỏi, điều gì thúc đẩy sự nhiệt tình của bạn để giúp đỡ người khác?Tôi hy vọng một ngày nào đó tôi có thể giống như bạn về công cụ này, hoặc bất cứ điều gì tôi đang làm trong tương lai. – orokusaki

0

Nếu bạn đang tìm kiếm thẳng lên danh sách hiểu biết, điều này sẽ thực hiện công việc:

L = ['foo', 'bar', 'baz', 'spam', 'eggs', 'cheese', 'yogurt'] 
[L[i*3 : (i*3)+3] for i in range((len(L)/3)+1) if L[i*3 : (i*3)+3]] 
# [['foo', 'bar', 'baz'], ['spam', 'eggs', 'cheese'], ['yogurt']] 
L = ['foo', 'bar', 'baz', 'spam', 'eggs', 'cheese'] 
# [['foo', 'bar', 'baz'], ['spam', 'eggs', 'cheese']] 
6

phiên bản này hoạt động với bất kỳ (có thể là lười biếng và không sliceable) iterable và tạo ra một lười biếng iterable (nói cách khác, đó là một máy phát điện và làm việc với tất cả các loại trình tự, bao gồm máy phát điện khác):

import itertools 

def paginate(iterable, page_size): 
    while True: 
     i1, i2 = itertools.tee(iterable) 
     iterable, page = (itertools.islice(i1, page_size, None), 
       list(itertools.islice(i2, page_size))) 
     if len(page) == 0: 
      break 
     yield page 

Một số ví dụ:

In [61]: list(paginate(my_sequence, 3)) 
Out[61]: [['foo', 'bar', 'baz'], ['spam', 'eggs', 'cheese'], ['yogurt']] 

In [62]: list(paginate(xrange(10), 3)) 
Out[62]: [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]] 
1

các grouper chức năng trong itertools tài liệu là thông minh và súc tích; vấn đề duy nhất là bạn có thể cần phải cắt giảm kết quả, như Alex Martelli đã chỉ ra. Tôi sẽ nghiêng về một giải pháp dọc theo dòng câu trả lời của Michał Marczyk, mặc dù tôi không hiểu tại sao điều đó lại không thể đơn giản hơn nhiều. Điều này phù hợp với tất cả các trường hợp tôi có thể quan niệm:

import itertools 

def paginate(seq, page_size): 
    i = iter(seq) 
    while True: 
     page = tuple(itertools.islice(i, 0, page_size)) 
     if len(page): 
      yield page 
     else: 
      return 
Các vấn đề liên quan