web-dev-qa-db-de.com

Wie erstelle ich eine Liste oder ein Tuple leerer Listen in Python?

Ich muss eine Liste oder einen Tupel mit Listen füllen. Etwas, das so aussieht:

result = []
firstTime = True
for i in range(x):
    for j in someListOfElements:
        if firstTime:
            result.append([f(j)])
        else:
            result[i].append(j)

Um es weniger elegant zu machen, dachte ich, ich würde eine Liste mit leeren Listen vorbelegen

result = createListOfEmptyLists(x)
for i in range(x):
    for j in someListOfElements:
        result[i].append(j)

Der Teil der Vorbelegung ist für mich nicht offensichtlich. Wenn ich result = [[]] * x mache, erhalte ich eine Liste von x-Verweisen auf dieselbe Liste, so dass die Ausgabe des Folgenden erfolgt

result[0].append(10)
print result

ist:

[[10], [10], [10], [10], [10], [10], [10], [10], [10], [10]]

Ich kann eine Schleife (result = [[] for i in range(x)]) verwenden, frage mich jedoch, ob eine "schleifenlose" Lösung existiert.

Ist der einzige Weg zu bekommen, wonach ich suche 

38
Boris Gorelik
result = [list(someListOfElements) for _ in xrange(x)]

Dadurch werden x verschiedene Listen mit jeweils einer Kopie von someListOfElements list erstellt (jedes Element in dieser Liste ist referenziert, aber die Liste ist eine Kopie).

Wenn es sinnvoller ist, ziehen Sie die Verwendung von copy.deepcopy(someListOfElements) in Betracht.

Generatoren und Listenverständnisse und Dinge werden durchaus als Pythonic betrachtet.

51
Will

Es gibt keine Möglichkeit, eine solche Liste ohne eine Schleife von some sort zu erstellen. Es gibt mehrere Möglichkeiten, die Schleife auszublenden, genauso wie [[]] * x die Schleife verbirgt. Es gibt das Listenverständnis, das die Schleife in einem Ausdruck "verbirgt" (etwas ist es zum Glück noch offensichtlich.) Außerdem gibt es map(list, [[]]*x), die zwei versteckte Schleifen hat (die in [[]] * x und die in map), die eine Kopie von jedem erstellt Liste mit list().)

Es besteht auch die Möglichkeit, die Liste der Listen nicht vorher zu erstellen. Die anderen Antworten decken bereits den einfachen Ansatz ab, aber wenn dies irgendwie nicht zu Ihren Bedürfnissen passt, gibt es andere Möglichkeiten. Sie können beispielsweise eine Funktion erstellen, die bei Bedarf eine leere Liste an die Liste result anfügt, und Folgendes aufrufen:

def append(L, idx, item):
    while len(L) <= idx:
        L.append([])
    L[idx].append(item)

for i in range(x):
    for j in someListOfElements:
        append(result, i, j)

Oder Sie könnten anstelle einer Liste eine collections.defaultdict(list) verwenden:

import collections
result = collections.defaultdict(list)
for i in range(x):
    for j in someListOfElements:
        result[i].append(j)

Dies hat den Vorteil, dass ein bereits vorhandener Typ verwendet wird, was weniger Arbeit bedeutet, aber es bedeutet, dass Sie jetzt ein Diktat (durch Ganzzahlen indiziert) anstelle einer Liste haben, die möglicherweise das ist, was Sie möchten. Oder Sie können eine Klasse erstellen, die sich fast wie eine Liste verhält, aber neue Listen an sich selbst anfügt, statt IndexError zu erhöhen, z.

import UserList
class defaultlist(UserList.UserList):
    def __getitem__(self, idx):
        while len(self) <= idx:
            self.append([])
        return UserList.UserList.__getitem__(self, idx)

result = defaultlist()
for i in range(x):
    for j in someListOfElements:
        result[i].append(j)
7
Thomas Wouters

Sie könnten eine schnelle Generatorfunktion schreiben. Dies hätte etwas anderes als diesen speziellen Fall, also werde ich es etwas verallgemeinern. Graben Sie dies:

def create(n, constructor=list):
    for _ in xrange(n):
        yield constructor()

Dann eine Liste von Listen erstellen,

result = list(create(10))

eine Liste mit leeren Diktaten erstellen,

result = list(create(20, dict))

und (der Vollständigkeit halber) eine Liste leerer Foos erstellen,

result = list(create(30, Foo))

Natürlich können Sie auch einen Tuple von den oben genannten machen. Es wäre nicht zu schwer, es zu erweitern, um Konstruktoren Argumente zu erlauben. Ich würde wahrscheinlich eine Funktion akzeptieren, die einen Index akzeptiert und die Argumente zurückgibt, die an den Konstruktor übergeben werden sollen.

Ein letzter Gedanke ist, dass, weil die einzige Anforderung, die wir an constructor stellen, ist, dass es sich um eine Callable handelt. Sie können sogar alles übergeben, was das zurückgibt, was Sie in Ihrer Liste wünschen. Eine gebundene Methode, die Ergebnisse für eine Instanz aus einer Datenbankabfrage abruft. Es ist eine recht nützliche kleine drei Zeilen Code. 

5
aaronasterling

Warum halten Sie es nicht einfach, indem Sie die Liste in der entsprechenden Schleife anhängen

result = []
for i in range(x):
    result.append([])
    for j in someListOfElements:
        result[i].append(j)

[Bearbeiten: Beispiel hinzufügen]

>>> someListOfElements = ['a', 'b', 'c']
>>> x = 3
>>> result = []
>>> for i in range(x):
...     result.append([])
...     for j in someListOfElements:
...         result[i].append(j)
... 
>>> 
>>> result
[['a', 'b', 'c'], ['a', 'b', 'c'], ['a', 'b', 'c']]
4
pyfunc

Bitte geben Sie runnable Beispielcode an, damit wir den Code selbst ausführen können, um schnell zu sehen, was Sie genau tun möchten. Es sieht so aus, als wollten Sie das nur:

result = []
for i in range(x):
    data = []
    for j in someListOfElements:
        data.append(j)
    # or data = [j for j in someListOfElements]
    result.append(data)
0
Glenn Maynard