2010-12-21 38 views
16

Das Gegenteil von Listenabflachung.Unterlisten erstellen

Gegeben eine Liste und eine Länge n geben Sie eine Liste von Unterlisten der Länge n zurück.

def sublist(lst, n): 
    sub=[] ; result=[] 
    for i in lst: 
     sub+=[i] 
     if len(sub)==n: result+=[sub] ; sub=[] 
    if sub: result+=[sub] 
    return result 

Ein Beispiel:

Wenn die Liste:

[1,2,3,4,5,6,7,8] 

und n:

3 

Return:

[[1, 2, 3], [4, 5, 6], [7, 8]] 

Gibt es einen eloquenteren/prägnanteren Weg?

Nebenbei bemerkt, was bevorzugt wird, wenn Listen Listen (im Kontext oben) anhängt:

list1+=[list2] 

Oder:

list1.append(list2) 

Da (nach Summerfeild des 'Programmierung in Python 3') Sie sind gleich?

Danke.

Antwort

15

Eine solche Liste von Listen könnten mit Hilfe der konstruierten ein list comprehension:

In [17]: seq=[1,2,3,4,5,6,7,8] 
In [18]: [seq[i:i+3] for i in range(0,len(seq),3)] 
Out[18]: [[1, 2, 3], [4, 5, 6], [7, 8]] 

Es gibt auch die grouper idiom:

In [19]: import itertools 
In [20]: list(itertools.izip_longest(*[iter(seq)]*3)) 
Out[20]: [(1, 2, 3), (4, 5, 6), (7, 8, None)] 

aber beachten Sie, dass fehlende Elemente mit dem Wert None gefüllt sind. izip_longest kann auch einen fillvalue Parameter verwenden, wenn etwas anderes als None gewünscht ist.


list1+=[list2] - unter Hinweis auf die Klammern diesmal - entspricht list1.append(list2). Meine höchste Priorität beim Schreiben von Code ist Lesbarkeit, nicht Geschwindigkeit. Aus diesem Grund würde ich mit list1.append(list2) gehen. Lesbarkeit ist jedoch subjektiv und hängt wahrscheinlich stark davon ab, welche Idiome Ihnen vertraut sind.

Zum Glück, in diesem Fall, Lesbarkeit und Geschwindigkeit scheinen zusammenfallen:

In [41]: %timeit list1=[1,2,3]; list1.append(list2) 
1000000 loops, best of 3: 612 ns per loop 

In [42]: %timeit list1=[1,2,3]; list1+=[list2] 
1000000 loops, best of 3: 847 ns per loop 
+0

Danke unutbu, muss lachen, wie trivial das ist mit dem Listenverständnis. Unterstreicht mein Bedürfnis, sie zu studieren. In Bezug auf + = vs append, verstehe ich den Unterschied, merke ich verglich list1 + = [list2] zu list1.append (list2), nicht list1 + = list2 und list1.append (list2). Danke tolle Antwort/Diskussion. –

+0

@Michael Puckett: Ups, ich habe den zweiten Teil Ihrer Frage falsch gelesen. Bearbeiten ... – unutbu

+0

Danke unutbu - append ftw. :) –

1

ich denke, die Split-Funktion tut, was Sie suchen (obwohl es mit jedem Iterator funktioniert und nicht nur Listen):

from itertools import islice 

def take(n, it): 
    "Return first n items of the iterable as a list" 
    return list(islice(it, n)) 

def split(it, size): 
    it = iter(it) 
    size = int(size) 
    ret = take(size, it) 
    while ret: 
     yield ret 
     ret = take(size, it) 

Edit: Ihre asside In Bezug auf, verwende ich list.append immer (bla), da es sich für mich idiomatischer anfühlt, aber ich glaube, dass sie funktional gleichwertig sind.

+2

die django dinge sieht nicht notwendig aus –

+0

@Xavier yup, ich habe es entfernt (ich war ursprünglich dies als Django Vorlage Filter) –

+0

Danke Gabriel. –

6

Wie wäre es die folgenden (wo x ist Ihre Liste):

[x[i:i+3] for i in range(0, len(x), 3)] 

Dies ist trivial für n!=3 zu verallgemeinern .

Was Ihre zweite Frage betrifft, sind sie gleichwertig, also denke ich, es ist eine Frage des Stils. Stellen Sie jedoch sicher, dass Sie nicht confusing append with extend sind.

+0

Dank aix, Liste Verständnis auf jeden Fall den Weg zu gehen. Es ärgert mich, dass ich nicht daran gedacht habe, sondern Trost darin finde, dass ich ein Python Noob bin. –

5

Diese Funktion jede Art von iterable nehmen können (nicht nur Sequenzen bekannter Länge):

import itertools 

def grouper(n, it): 
    "grouper(3, 'ABCDEFG') --> ABC DEF G" 
    it = iter(it) 
    return iter(lambda: list(itertools.islice(it, n)), []) 

print(list(grouper(3, [1,2,3,4,5,6,7,8,9,10]))) 
# [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]] 
+0

Dank Tokland, gut zu wissen. –

0

Ich weiß, es sieht aus wie ein brainfuck, ist aber Werke:

>>> a = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15] 
>>> n = 3 
>>> [i for j in [[a[t:t+n] for x in a[:1:t+1] if (t%n)==False] for t in range(len(a))] for i in j] 
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15]] 

>>> n = 4 
>>> [i for j in [[a[t:t+n] for x in a[:1:t+1] if (t%n)==False] for t in range(len(a))] for i in j] 
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15]] 
0

Für einige In bestimmten Fällen könnte es nützlich sein, das numpy-Paket zu verwenden. In diesem Paket haben Sie eine reshape Routine:

import numpy as np 
x = np.array([1,2,3,4,5,6]) 
np.reshape(x, (-1,3)) 

Diese Lösung ist jedoch wird Ihre Liste nicht-Pad, wenn es nicht eine Multiplikation von n ist.

+0

Numpy ist ein bisschen Overkill dafür. Wie auch immer, es ist gut, über die angegebene Funktionalität zu wissen. Danke joker5. –

2

Haben Sie von boltons gehört?

Boltons ist ein Satz von reinem Python-Dienstprogramme in dem gleichen Geist wie - und doch auffallend von fehlt - die die Standard-Bibliothek

Es hat, was Sie wollen, eingebaut, genannt chunked

from boltons import iterutils 

iterutils.chunked([1,2,3,4,5,6,7,8], 3) 

Ausgang:

[[1, 2, 3], [4, 5, 6], [7, 8]] 

Und was attraktiver in boltons ist, dass es chunked als Iterator hat, genannt chunked_iter, so dass man das Ganze im Speicher nicht gespeichert werden muß. Ordentlich, oder?

Verwandte Themen