0

Um zu vermeiden, eine neue Liste gleicher Dimension zu erstellen, frage ich mich, ob Mehrfachzuweisung eine einfache Transponierfunktion ermöglichen könnte, die ein bestehendes Array modifiziert. Diese Funktion soll als eine Methode für eine Klasse mit einer state -Eigenschaft fungieren, die eine multidimensionale Liste ist. Etwas wie dieses:Ist es möglich, in Python mehrere Zuweisungen zu verwenden, um eine mehrdimensionale Liste zu transponieren?

def transpose(self): 
    for i in range(dim): 
     for j in range(dim): 
      self.state[i][j], self.state[j][i] = self.state[j][i], self.state[i][j] 
    return self 

Obwohl das läuft, scheint mir die gleiche Liste zurück zu geben. Ich bin auch daran interessiert, warum so etwas theoretisch nicht funktionieren sollte/sollte. Ich habe bereits andere effiziente Mittel zur Umsetzung von Listen untersucht (zip, usw.), dies ist eher eine aufgabenspezifische Frage. Danke für Ihre Hilfe.

+0

Hier ein Rezept: https://rosettacode.org/wiki/Matrix_transposition# Python – noumenal

Antwort

0

Das funktioniert, das Objekt, auf das sich self.state bezieht, ändert sich einfach nicht. Wenn Sie ein Zwischenobjekt für die Liste verwenden, self.state kann es Punkt werden neu zugeordnet:

def transpose(self): 
    result = [[None for column in row] for row in self.state] 
    for i in range(len(self.state)): 
     for j in range(len(self.state[i])): 
      result[j][i], result[i][j] = self.state[i][j], self.state[j][i] 
    self.state = result 
1

Sie jedes Element sind Querungs das heißt, Sie zweimal tauschen wird.

In Beispiel bei (i=0, j=1) wird tauschen Sie (i=0, j=1) < ->(i=0, j=1)wieder ->(i=1, j=0) und bei (i=1, j=0) Sie (i=1, j=0) < tauschen wird.

Ändern Sie die zweite Schleife zu for j in range(i + 1, dim), um nur die obere rechte Hälfte (Dreieck) zu durchlaufen.

0

Haftungsausschluss: Ich habe keine der oben genannten Code getestet, also entschuldige ich mich, wenn es einen Fehler gibt. Außerdem habe ich die Annahme, dass wir über Python reden 3 hier, aber ich denke, dass dieser Code noch in Python funktionieren soll 2.


Nicht ohne zusätzlichen Funktionsaufruf.

Zum Beispiel, sagen wir mal Sie eine Matrix Klasse wie folgt:

from copy import copy 

class Matrix: 
    def __init__(self, rows): 
     self._rows = rows 

    @property 
    def rows(self): 
     return list(map(copy, self._rows)) 

    @rows.setter 
    def rows(self, rows): 
     self._rows = list(map(copy, rows)) 

    def cols(self): 
     return list(map(list, zip(*self._rows))) 

    @cols.setter 
    def cols(self, cols): 
     self._rows = list(map(list, zip(cols))) 

    def transpose(self): 
     self.cols = self._rows 

Die transponieren Funktion würde nicht einmal verwenden müssen Liste Auspacken. Aber das verwendet immer noch zip, von dem du erwähnt hast, dass du darüber nachdenkst, es abzuschaffen.

Wenn Sie das Entpacken der Liste verwenden möchten, müssen Sie wissen, wie viele Werte entpackt werden. Wenn Sie also variable Dimensionen unterstützen, ist dies kein No-Go. Andernfalls müssen Sie die Änderungen fest codieren.

Aber es gibt ein anderes Problem zur Hand. Da das Transponieren die Dimensionen einer nicht-quadratischen Matrix ändern würde, können Sie nicht elementweise tauschen. Ein IndexError würde in einer solchen Situation auftreten. Sie müssten zeilen- oder spaltenweise tauschen. Um dies zu tun, müssten Sie zu einem bestimmten Zeitpunkt eine Kopie der Spalten oder Zeilen erstellen (wie im obigen Code gezeigt - beachten Sie, dass die Getter-Kopien nicht notwendig sind).

Es gibt eine Technik, die Sie verwenden könnten. Sie können Ihre mehrdimensionale Liste als eine eindimensionale Liste speichern und einfach mithilfe von Mathematik bestimmen, wo eine Zeile (oder Spalte) beginnt.Zum Beispiel könnten Sie folgendermaßen vorgehen:

class Matrix: 
    def __init__(self, values, number_of_columns, number_of_rows): 
     self._values = values 
     self._number_of_columns = number_of_columns 
     self._number_of_rows = number_of_rows 

    @property 
    def rows(self): 
     return [self._values[i * self._number_of_rows:(i + 1) * self._number_of_rows] for i in range(self._number_of_rows)] 

    @property 
    def cols(self): 
     return [self._values[i::self._number_of_columns] for i in range(self._number_of_columns)] 

    def transpose(self): 
     for i in range(self._number_of_rows): 
      self._values[i * self._number_of_rows:(i + 1) * self._number_of_rows], self._values[i::self._number_of_rows] = self._values[i::self._number_of_columns], self._values[i * self._number_of_columns:(i + 1) * self._number_of_columns] 
     self._number_of_columns, self._number_of_rows = self._number_of_rows, number_of_columns 

Obwohl die erste Iteration Swaps Werte zu ihren richtigen Plätzen, in einer nicht-quadratischen Matrix, sind einige Werte verloren. Betrachten Sie zum Beispiel eine Matrix, die wie folgt aufgebaut ist: Matrix(list(range(6)), 3, 2). wie folgt

Jeder Durchlauf:

  1. self._values == [0, 3, 1, 3, 2, 5]
  2. self._values == [0, 3, 3, 2, 2, 5]

Beachten Sie, dass sie die Werte an den richtigen Stellen auf dem ersten Durchgang bringt. Aber es überschreibt Werte, die noch verschoben werden müssen. Der einzige Weg, dies zu vermeiden, ist eine Kopie zu erstellen. So Sie könnte ändern, um die transpose Methode funktioniert wie folgt:

def transpose(self): 
     new_values = [] 
     for i in range(self._number_of_rows): 
      new_values.extend(self._values[i::self._number_of_columns]) 
     self._values = new_values 
     self._number_of_columns, self._number_of_rows = self._number_of_rows, number_of_columns 

Aber das ist extrem verworren und schwer zu debuggen. Also die Moral der Geschichte ist einfach zu verwenden self.state = list(zip(*self.state)) -Es ist ziemlich einfach zu lesen und schwer zu vermasseln-oder was Sie bereits in Ihrer transpose Methode haben.


Auf den zweiten Blick scheint es, dass Ihre transpose Methode eine doppelte Transposition der Fall ist. Und natürlich die Umsetzung einer Transposition einer Matrix M ist identisch mit M. Sie müssen die Decke machen die innere Schleife kleiner:

def transpose(self): 
    for i in range(dim): 
     for j in range(i): 
      self.state[i][j], self.state[j][i] = self.state[j][i], self.state[i][j] 
    return self 
Verwandte Themen