如何切换二维数组中的行和列?

How do I switch rows and columns in a 2D array?

我正在编写一个代码,该代码将创建一个用于 3D 打印的视觉 Sierpinski 三角形,为了让它工作,我必须使用 Pascal 三角形算法来创建一个数组,以便我可以用来告诉我的算法这将在不放置三角形的地方创建我的三角形。

无论如何问题是,我排列三角形的代码是按列而不是像 Pascal 算法那样按行创建三角形的,所以我只是想通过一个重新排列 Pascal 数组的子程序来快速修复.我只是不知道如何去做,因为我不确定如何避免 index out of range 错误。

这是为 Pascal 三角形创建数组的代码。

TL:DR 我正在尝试重新排列一个数组,其中行是列,列是行

def pascal(n):
    """Prints out n rows of Pascal's triangle."""
    row = [1]
    global array
    array = [[0 for x in range(int(n))] for y in range(int(n))]
    array[0]=row
    k = [0]
    for x in range(int(max(n,0)-1)):
       row=[l+r for l,r in zip(row+k,k+row)]
       array[x+1]=row
    return 1

这是打印数组的输出。我只想让行成为列,让列成为行

[[1],
 [1, 1],
 [1, 2, 1],
 [1, 3, 3, 1],
 [1, 4, 6, 4, 1],
 [1, 5, 10, 10, 5, 1],
 [1, 6, 15, 20, 15, 6, 1],
 [1, 7, 21, 35, 35, 21, 7, 1]]

如果您对该项目感兴趣,请查看完整代码,但需要 rhinoscriptsyntax 才能制作模型。

import rhinoscriptsyntax as rhino
import math

obj = rhino.GetObject("Select object to transform", preselect=True)
scale = 3
n=math.pow(3,scale)
def pascal(n):
   """Prints out n rows of Pascal's triangle."""
   row = [1]
   global array
   array = [[0 for x in range(int(n))] for y in range(int(n))]
   array[0]=row
   k = [0]
   for x in range(int(max(n,0)-1)):
      row=[l+r for l,r in zip(row+k,k+row)]
      array[x+1]=row
   return 1
pascal(math.pow(2,scale))
print array
def remakePascal():
    pass
my_horizontalVector = [[1,0,0,6],
           [0,1,0,0],
           [0,0,1,0],
           [0,0,0,1]]

my_tsfm = [[1,0,0,0],  #identity
           [0,1,0,0],
           [0,0,1,0],
           [0,0,0,1]]


def makeTriangle(scale,obj):
    w=1/scale
    h=1/scale
    tsfm= [[w,0,0,0],   #scale about origin
            [0,h,0,0],
            [0,0,1,0],
            [0,0,0,1]]
    output= rhino.XformMultiply(my_tsfm,tsfm)
    new_obj=rhino.TransformObject(obj,output,copy=True)
    return new_obj
def placeObj(i):
    my_moveUpVector = [[1,0,0,(3/scale)*i],
           [0,1,0,(4/scale)*i],
           [0,0,1,0],
           [0,0,0,1]]
    vector = rhino.XformMultiply(my_tsfm,my_moveUpVector)
    return vector
n=0
for i in range(int(math.pow(2,scale))):
    if(i>0):
       hPlace=rhino.XformMultiply(my_tsfm,my_horizontalVector)
       obj = rhino.TransformObject(obj,hPlace)
    factor = int(math.pow(2,scale))-n
    for j in range(factor):
        if():
            pass
        else:
            Vertobj=makeTriangle(scale,obj)
            tsfm = rhino.TransformObject(Vertobj,placeObj(j),copy=True)
    n=n+1

你可能想要这样的东西:

def pascal(n):
    a = [[int(i==0) for j in range(n)] for i in range(n)]
    for i in range(n):
        for j in range(1, 1+i):
            a[j][i] = a[j][i-1] + a[j-1][i-1]

    for line in a: print(line)

pascal(7)

这会打印:

[1, 1, 1, 1, 1, 1, 1]
[0, 1, 2, 3, 4, 5, 6]
[0, 0, 1, 3, 6, 10, 15]
[0, 0, 0, 1, 4, 10, 20]
[0, 0, 0, 0, 1, 5, 15]
[0, 0, 0, 0, 0, 1, 6]
[0, 0, 0, 0, 0, 0, 1]

对于转置方阵,简单的解决方案是

transposed_array = zip(*array)

这种方法不适用于三角数据,因为 zip 在行长度不等时不会插入填充。 itertools.izip_longest 但是:

import itertools
transposed_array = itertools.izip_longest(*array)

默认情况下 izip_longest 填充 None,因此您会得到如下结果:

[(1, 1, 1, 1, 1),
 (None, 1, 2, 3, 4),
 (None, None, 1, 3, 6),
 (None, None, None, 1, 4),
 (None, None, None, None, 1)]

如果您愿意,可以删除具有列表理解的 None 个条目:

no_nones = [[item for item in row if item is not None] for row in transposed_array]

还剩下:

[[1, 1, 1, 1, 1],
 [1, 2, 3, 4],
 [1, 3, 6],
 [1, 4],
 [1]]

如果您喜欢用 0(或其他任何内容)填充,请将其指定为 itertools.izip_longestfillvalue 关键字参数;例如

list(itertools.izip_longest(*array, fillvalue=0))

returns

[(1, 1, 1, 1, 1),
 (0, 1, 2, 3, 4),
 (0, 0, 1, 3, 6),
 (0, 0, 0, 1, 4),
 (0, 0, 0, 0, 1)]

我在这里假设元组列表适用于您的目的。如果你需要内部可变,你可以通过列表理解来获得它,例如:

list_of_lists = [list(row) for row in transposed_array]

你可以如图那样做。它的工作原理是首先使数组呈正方形,以便所有行都具有相同数量的元素。然后使用内置的 zip() 函数转置行和列,最后删除它最初添加的元素。

另请注意,我删除了全局变量 array 的使用。最好避免使用全局变量。

from pprint import pprint

def pascal(n):
    """Creates n rows of Pascal's triangle."""
    array = [None for y in range(n)]

    row = [1]
    array[0] = row
    k = [0]
    for x in range(max(n, 0)-1):
       row = [l+r for l,r in zip(row+k, k+row)]
       array[x+1] = row

    return array

def transpose(array):
    array = array[:]  # make copy to avoid changing original
    n = len(array)
    for i, row in enumerate(array):
        array[i] = row + [None for _ in range(n - len(row))]

    array = zip(*array)

    for i, row in enumerate(array):
        array[i] = [elem for elem in row if elem is not None]

    return array

array = pascal(8)
array = transpose(array)
pprint(array)

输出:

[[1, 1, 1, 1, 1, 1, 1, 1],
 [1, 2, 3, 4, 5, 6, 7],
 [1, 3, 6, 10, 15, 21],
 [1, 4, 10, 20, 35],
 [1, 5, 15, 35],
 [1, 6, 21],
 [1, 7],
 [1]]

每行的长度与最大行匹配并用零填充后,您可以转置行和列。

工作代码如下。 numpy_fillna 函数源自 this SO post.

import numpy as np
x = [[1],
 [1, 1],
 [1, 2, 1],
 [1, 3, 3, 1],
 [1, 4, 6, 4, 1],
 [1, 5, 10, 10, 5, 1],
 [1, 6, 15, 20, 15, 6, 1],
 [1, 7, 21, 35, 35, 21, 7, 1]]

a = np.array(x)

def numpy_fillna(data):
    # Get lengths of each row of data
    lens = np.array([len(i) for i in data])

    # Mask of valid places in each row
    mask = np.arange(lens.max()) < lens[:,None]

    # Setup output array and put elements from data into masked positions
    out = np.zeros(mask.shape, dtype=data.dtype)
    out[mask] = np.concatenate(data)
    return out

结果

>>> numpy_fillna(a).T
array([[1, 1, 1, 1, 1, 1, 1, 1],
       [0, 1, 2, 3, 4, 5, 6, 7],
       [0, 0, 1, 3, 6, 10, 15, 21],
       [0, 0, 0, 1, 4, 10, 20, 35],
       [0, 0, 0, 0, 1, 5, 15, 35],
       [0, 0, 0, 0, 0, 1, 6, 21],
       [0, 0, 0, 0, 0, 0, 1, 7],
       [0, 0, 0, 0, 0, 0, 0, 1]], dtype=object)
>>>