将数组广播到不同形状(添加“伪”维度)

7 投票
2 回答
3554 浏览
提问于 2025-04-17 14:35

在Python中(使用numpy),我可以把一个数组变成不同的形状:

>>> import numpy as np
>>> a = np.array([2,3,4])
>>> b = np.zeros((3,2))
>>> b[:,:] = np.zeros((3,2))
>>> b[:,:] = a[:,np.newaxis]  #<-- np.newaxis allows `a` to be "broadcasted" to the same shape as b.
>>> b
array([[ 2.,  2.],
       [ 3.,  3.],
       [ 4.,  4.]])
>>> c = np.zeros((2,3))
>>> c[:,:] = a[np.newaxis,:]
>>> c
array([[ 2.,  3.,  4.],
       [ 2.,  3.,  4.]])

有没有办法在Fortran中实现同样的效果?我有一个子程序,它需要传入一个2D数组——我想把我的1维数组“扩展”成2维,就像我上面展示的那样。看起来这可能很重要,我的2D数组确实有一个明确的接口。

顺便提一下,我原以为这个功能可能可以通过reshape这个内置函数来实现——类似于:

real,dimension(3) :: arr1d
reshape(arr1d, (/3,3/), order=(/1,/1))

但是在阅读文档后,我觉得这可能不行,因为order似乎需要包含从1到"N"的所有数字。

编辑:为了更清楚一点,我在寻找一种简单的方法来对输入a进行几个变换,使得:

情况1

b(i,j) .eq. a(i)  !for all j, or even just j=1,2

情况2

b(j,i) .eq. a(i)  !for all j, or even just j=1,2

如果能处理任意维度,那就更好了:

b(i,j,k) .eq. a(i,j)
b(i,k,j) .eq. a(i,j)

等等。

1免责声明——我其实没有什么特别的能力可以给回答者加分;-)

2 个回答

1

reshape这个功能可以让你把一维数组变成二维数组。如果你用的是比较新的Fortran编译器,还有一种指针的技巧可以用。指针提供了一种新的方式来引用存储空间,这样就不用复制数据了。这个方法叫做“指针边界重映射”。下面是一个例子:

program array_tst

  integer, dimension (4), target :: array_1d
  integer, dimension (:,:), pointer :: array_2d

  array_1d = [ 1, 2, 3, 4 ]

  array_2d (1:2, 1:2) => array_1d

  write (*, *) array_2d (1,1), array_2d (1,2), array_2d (2,1), array_2d (2,2)

end program array_tst

另外,你可以查看 在Fortran中改变数组维度

补充说明:针对评论的回复……如果你不介意复制数组,这里有使用reshape的方法:

program array_reshape

  integer, dimension (4) :: array_1d
  integer, dimension (2, 2) :: array_2d

  array_1d = [ 1, 2, 3, 4 ]

  array_2d = reshape ( array_1d, [2,2] )

  write (*, *) array_2d (1,1), array_2d (1,2), array_2d (2,1), array_2d (2,2)

end program array_reshape
6

我不太确定你想要实现什么,但这里有几个片段可能会对你有帮助。

reshape 这个函数可以接受一个可选的参数,叫做 pad,这个参数可以用来提供在你把数组的形状改变成比原来更多元素时所需的“额外”元素,比如从 3x4 变成 2x4x2。

你可能还会对 spread 函数感兴趣,它的作用是“提升”数组的维度,也就是说,它可以把一个 N 维的数组变成一个 N+1 维的数组。你第二个代码片段可以改写成:

array2d = spread(array1d,2,2)

在这个例子中,第二个参数是你想要沿着哪个维度来扩展第一个参数,以生成输出。第三个参数是你要生成多少个输入数组的副本。

另外,调用 spread 的时候,可能应该是 spread(array1d,1,2),我没有检查过。

编辑:这是对提问者修改问题后的回应。

这两种情况,1 和 2,分别是通过在维度 2 和 1 上进行扩展来满足的。在 Fortran 中:

b = spread(a,2,j)

还有

b = spread(a,1,j)

因为 spread 返回的数组的维度比它第一个参数的维度大 1,所以它提供了所需的任意维度。不过,由于展示 3 维及以上的数组会占用很多空间,我就不展示了。

撰写回答