如何在一维数组中“展平”或“索引”3维数组?

Posted

技术标签:

【中文标题】如何在一维数组中“展平”或“索引”3维数组?【英文标题】:How to "flatten" or "index" 3D-array in 1D array? 【发布时间】:2011-11-14 03:07:15 【问题描述】:

我正在尝试将 3D 数组展平为 1D 数组,用于我的游戏中的“块”系统。这是一个 3D 块游戏,基本上我希望块系统与 Minecraft 的系统几乎相同(但是,无论如何,这不是 Minecraft 克隆)。在我之前的 2D 游戏中,我使用以下算法访问了扁平数组:

Tiles[x + y * WIDTH]

但是,这显然不适用于 3D,因为它缺少 Z 轴。我不知道如何在 3D 空间中实现这种算法。宽度、高度和深度都是常数(宽度与高度一样大)。

只是x + y*WIDTH + Z*DEPTH 吗?我的数学很差,我刚刚开始 3D 编程,所以我很迷茫:|

PS。这样做的原因是我正在循环并通过索引从中获取很多东西。我知道一维数组比多维数组更快(出于我不记得的原因:P)。尽管这可能不是必需的,但我希望性能尽可能好:)

【问题讨论】:

我是否正确地说您希望 3D 数组适合 1D 数组? 为什么不用3D数组? @DMan 是的,没错。 【参考方案1】:

这里有一个 Java 解决方案,可以同时满足您的要求:

从 3D 到 1D 从 1D 到 3D

下面是我选择遍历 3D 矩阵的路径的图解说明,单元格按遍历顺序编号:

转换函数:

public int to1D( int x, int y, int z ) 
    return (z * xMax * yMax) + (y * xMax) + x;


public int[] to3D( int idx ) 
    final int z = idx / (xMax * yMax);
    idx -= (z * xMax * yMax);
    final int y = idx / xMax;
    final int x = idx % xMax;
    return new int[] x, y, z ;

【讨论】:

在这个答案中不清楚 xMax 是指WIDTH 还是WIDTH-1【参考方案2】:

算法大体相同。如果你有一个 3D 数组 Original[HEIGHT, WIDTH, DEPTH] 那么你可以把它变成 Flat[HEIGHT * WIDTH * DEPTH] by

Flat[x + WIDTH * (y + DEPTH * z)] = Original[x, y, z]

顺便说一句,在 .NET 中,您应该更喜欢数组数组而不是多维数组。性能差异显着

【讨论】:

您能否指出一些讨论性能差异的来源?此外,您不应仅根据性能做出决定。 ***.com/questions/597720/… 和 ***.com/questions/468832/… @svick:在提供的链接中可以看到一些来源。我的表现说明只是一个旁白,而不是主要建议。锯齿状数组具有几乎相同的语法(original[x][y][z]),但需要更多的工作来初始化。但是,性能优势可能会变得非常明显(加速 2-5 倍),具体取决于使用情况。 如果HEIGHT对应Y维度,应该是:Flat[x + WIDTH * (y + HEIGHT * z)] = Original[x, y, z]【参考方案3】:

我认为以上内容需要稍作修正。假设您的高度为 10,宽度为 90,一维数组将为 900。根据上述逻辑,如果您位于数组 9 + 89*89 的最后一个元素处,显然这大于 900。正确的算法是:

Flat[x + HEIGHT* (y + WIDTH* z)] = Original[x, y, z], assuming Original[HEIGHT,WIDTH,DEPTH] 

具有讽刺意味的是,如果您是 HEIGHT>WIDTH,您将不会遇到溢出,只会完成疯狂的结果;)

【讨论】:

我无法对真正的正确答案进行投票或评论,但马丁认为它是正确的,当前选择的答案是错误的。本质上:data[x][y][z] = data[x + ymaxX + zmaxX*maxY] 是的,目前的答案是错误的,应该是高度而不是深度。我花了很长时间才弄清楚这一点,因为这是我第一次真正使用错误的 SO 答案来编写代码>. 【参考方案4】:

x + y*WIDTH + Z*WIDTH*DEPTH。将其可视化为一个长方体:首先沿着x 遍历,然后每个y 是一个“线”width 步长,每个z 是一个“平面”WIDTH*DEPTH 步长。

【讨论】:

【参考方案5】:

你快到了。您需要将 Z 乘以 WIDTH DEPTH:

Tiles[x + y*WIDTH + Z*WIDTH*DEPTH] = elements[x][y][z]; // or elements[x,y,z]

【讨论】:

你能帮我确认一下 4D 或 5D 等的模式是什么【参考方案6】:

正确的算法是:

Flat[ x * height * depth + y * depth + z ] = elements[x][y][z] 
where [WIDTH][HEIGHT][DEPTH]

【讨论】:

测试了几乎所有其他答案,只有这个将嵌套的 for 循环(x 这是正确答案【参考方案7】:

TL;DR

正确答案可以用多种方式书写,但我最喜欢它的书写方式很容易理解和可视化。准确答案如下:

(width * height * z) + (width * y) + x

TS;DR

可视化它:

someNumberToRepresentZ + someNumberToRepresentY + someNumberToRepresentX

someNumberToRepresentZ 表示我们在哪个矩阵上 (depth)。要知道我们在哪个矩阵上,我们必须知道每个矩阵有多大。一个矩阵是 2d 大小的 width * height,很简单。要问的问题是“在我所在的矩阵之前有多少个矩阵?”答案是z

someNumberToRepresentZ = width * height * z

someNumberToRepresentY 表示我们在哪一行 (height)。要知道我们在哪一行,我们必须知道每行有多大:每行是 1d,大小为width。要问的问题是“在我所在的行之前有多少行?”。答案是y

someNumberToRepresentY = width * y

someNumberToRepresentX 表示我们在哪一列 (width)。要知道我们在哪一列,我们只需使用x

someNumberToRepresentX = x

我们当时的可视化

someNumberToRepresentZ + someNumberToRepresentY + someNumberToRepresentX

变成

(width * height * z) + (width * y) + x

【讨论】:

【参考方案8】:

上面 Samuel Kerrien 的正向和反向变换几乎是正确的。下面包含一个更简洁(基于 R)的转换图以及一个示例(“a %% b”是模运算符,表示 a 除以 b 的余数):

dx=5; dy=6; dz=7  # dimensions
x1=1; y1=2; z1=3  # 3D point example
I = dx*dy*z1+dx*y1+x1; I  # corresponding 2D index
# [1] 101
x= I %% dx; x  # inverse transform recovering the x index
# [1] 1
y = ((I - x)/dx) %% dy; y  # inverse transform recovering the y index
# [1] 2
z= (I-x -dx*y)/(dx*dy); z  # inverse transform recovering the z index
# [1] 3

注意除法 (/) 和模块 (%%) 运算符。

【讨论】:

【参考方案9】:

为了更好地理解 1D 数组中 3D 数组的描述(我猜最佳答案中的深度是指 Y 大小)

IndexArray = x + y * InSizeX + z * InSizeX * InSizeY;

IndexArray = x + InSizeX * (y + z * InSizeY);

【讨论】:

【参考方案10】:

m[x][y][z] = 数据[xYZ + yZ + z]

x-picture:
0-YZ
.
.
x-YZ

y-picture 

0-Z
.
.
.
y-Z


summing up, it should be : targetX*YZ + targetY*Z + targetZ  

【讨论】:

以上是关于如何在一维数组中“展平”或“索引”3维数组?的主要内容,如果未能解决你的问题,请参考以下文章

EXCEL 数组和维数

Python计算两个numpy数组的交集(Intersection)实战:两个输入数组的交集并排序获取交集元素及其索引如果输入数组不是一维的,它们将被展平(flatten),然后计算交集

如何正确连接两个一维数组而不展平?

使用rest参数将参数展平为一维数组

在 PHP 中将多维关联数组展平为一维引用数组

如何按希尔伯特曲线的顺序将二维矩阵(n x n)展平为一维数组?