2010-09-19 10 views
7

Ich möchte in der Lage sein, eine Sequenz wie folgt zu nehmen:Paginieren Sie so oder gibt es einen besseren Algorithmus?

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

Verwenden Sie eine Funktion wie:

my_paginated_sequence = get_rows(my_sequence, 3) 

So erhalten Sie:

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

Dies ist, was ich gerade erfunden habe Durchdenken:

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, dachte nicht, das hinzuzufügen. Bist du zufällig ein Ninja? – orokusaki

+0

mögliches Duplikat von [Mehrere Objekte gleichzeitig aus einem iterierbaren Objekt ausgeben?] (Http://stackoverflow.com/questions/2202461/yield-multiple-objects-at-a-time-from-aniterable-object) –

+0

mögliche Duplikate von [Wie teilen Sie eine Liste in Python in gleich große Stücke?] (Http://stackoverflow.com/q/312443/54262) –

Antwort

11

Wenn Sie wissen, dass Sie eine schneidbar Sequenz (Liste oder Tupel),

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

Das ist natürlich ein Generator, also wenn Sie unbedingt eine Liste als Ergebnis benötigen, verwenden Sie natürlich list(getrows_byslice(seq, 3)) oder dergleichen.

Wenn das, was Sie beginnen mit einem generischen iterable ist, die itertools recipes bietet Hilfe mit dem grouper Rezepte ...:

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) 

(wieder, werden Sie list dazu aufrufe müssen, wenn eine Liste ist, was du willst natürlich).

Da Sie eigentlich wollen, dass das letzte Tupel abgeschnitten und nicht aufgefüllt wird, müssen Sie die abschließenden Füllwerte vom allerletzten Tupel "trimmen".

+0

sehen, was ich über Jedi meine. Ich habe das Gefühl, dass ich niemals in der Lage sein werde, sowas direkt aus meinem Gehirn zu machen. Hast du dich jemals wieder so gefühlt? – orokusaki

+0

@orokusaki, natürlich - aber dann habe ich angefangen, die Dokumente zu lesen (erinnere dich, dass die 'Grouper'-Funktion direkt aus der Dokumentation zitiert wird! -). –

+1

Außerdem spreche ich mit meinem Bruder am Telefon darüber, wie hilfreich Sie für die Python-Gemeinschaft als Ganzes sind. Wir wundern uns beide, was treibt dich dazu an, anderen zu helfen?Ich hoffe, dass ich eines Tages mit dir zusammen sein kann, oder was auch immer ich in der Zukunft mache. – orokusaki

0

Wenn Sie nach gerade nach oben Liste Verständnis sucht, wird dies die Arbeit machen:

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

Diese Version funktioniert mit jedem (möglicherweise faul und nicht schneidbar) iterable und erzeugt einen faulen iterable (mit anderen Worten, es ist ein Generator ist und arbeitet mit allen Arten von Sequenzen, einschließlich anderen Generatoren):

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 

Einige Beispiele:

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

Die grouper Funktion in den itertools docs ist klug und prägnant; Das einzige Problem ist, dass Sie die Ergebnisse möglicherweise kürzen müssen, wie Alex Martelli darauf hinwies. Ich würde zu einer Lösung nach Michał Marczyks Antwort neigen, obwohl ich nicht verstehe, warum das nicht viel einfacher gemacht werden kann. Dies funktioniert für alle Fälle, die ich mir vorstellen kann:

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