0

爲了避免創建一個等維的新列表,我想知道是否多個賦值可以允許一個簡單的轉置函數來修改一個正在退出的數組。此功能旨在用作具有屬性爲多維列表的state屬性的類的方法。這樣的事情:是否可以在Python中使用多個賦值來轉置多維列表?

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 

雖然運行這似乎給我回相同的列表。我也很感興趣,爲什麼這樣的事情應該/不應該在理論上工作。我已經研究了轉移列表的其他有效方法(zip等),這更多的是一個特定於任務的問題。謝謝你的幫助。

+0

這裏有一個配方:https://rosettacode.org/wiki/Matrix_transposition#蟒蛇 – noumenal

回答

0

這是行不通的,self.state引用的對象不會改變。如果你使用一箇中間對象的名單,self.state可以被重新分配它指向:

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

您traverseing的每一個元素,這意味着你將交換兩次。

在例如在(i=0, j=1)您將交換 (i=0, j=1) < - >(i=1, j=0)(i=1, j=0)你會掉 (i=1, j=0) < - >(i=0, j=1)再次

將第二個循環更改爲for j in range(i + 1, dim)以僅遍歷右上角的一半(三角形)。

0

免責聲明:我還沒有測試過任何上面的代碼,所以如果有錯誤,我很抱歉。此外,我提出,我們正在談論的Python 3這裏的假設,但我認爲這個代碼應該仍然在Python 2


不正常工作沒有額外的函數調用。

例如,假設你有一個Matrix類,如下所示:

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 

變調功能甚至不需要使用列表拆包。但是這仍然使用zip,你提到你正在考慮廢除。

如果你想使用列表解包,你必須知道有多少值將被解壓縮。因此,如果你支持可變維度,那麼這是一個不行。否則,您必須對更改進行硬編碼。

但還有另一個問題。由於移調會改變非方形矩陣的尺寸,因此不能進行按元素交換。在這種情況下會發生IndexError。你必須做行或列交換。要做到這一點,你必須在某個時刻製作一個列或行的副本(如上面的代碼所示 - 注意getter副本不是必需的)。

有一種技術可以使用。您可以將多維列表存儲爲一維列表,然後使用數學來確定行(或列)的起始位置。例如,你可以做到以下幾點:

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 

雖然第一次迭代掉期值他們適當的地方,在一個非方陣,一些值都將丟失。例如,考慮構造如Matrix(list(range(6)), 3, 2)的矩陣。

每一趟如下:

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

注意,它把這些值在第一次傳遞正確的地方。但它會覆蓋尚未移動的值。避免這種情況的唯一方法是複製。所以,你可以改變transpose方法的工作方式如下:

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 

但是,這是非常令人費解和難以調試。所以這個故事的寓意是僅僅使用self.state = list(zip(*self.state))-它很容易閱讀,很難搞定 - 或者你的方法已經有了。


在第二眼,看來你transpose方法做了雙重換位。當然,基體M的換位的換位是相同的M.你需要讓天花板內環較小:

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 
相關問題