[英]Convert 3D array to 2D array
I have a rank 3 int array array[9][3][3]
and I want to convert it into a rank 2 array arrayConvt[9][9]
by removing the major axis (rather than the middle axis).我有一个秩为 3 的 int 数组
array[9][3][3]
,我想通过删除主轴(而不是中轴)将它转换为一个秩为 2 的数组arrayConvt[9][9]
。 To make a 9x9 array rather than 3x27, imagine array
broken up into 3 equal parts, each laid out into arrayConvt
before the next.要制作 9x9 数组而不是 3x27,想象将
array
分成 3 个相等的部分,每个部分在下一个之前布局到arrayConvt
。 Note that the middle arrays ( array[i]
) do not remain contiguous in arrayConvt
, but the innermost arrays ( array[i][j]
) do.请注意,中间数组 (
array[i]
) 在arrayConvt
不保持连续,但最里面的数组 ( array[i][j]
) 保持连续。
One way to visualize it is to look at array
as an array of 9 blocks.可视化它的一种方法是将
array
视为 9 个块的数组。 I want to recombine the blocks left-to-right, top-to-bottom:我想从左到右,从上到下重新组合块:
How can I reshape array
according to this mapping?如何根据此映射重塑
array
?
The code sample below provides data to work with and the desired result:下面的代码示例提供了要使用的数据和所需的结果:
public static void main(String[] args) {
int[][][] array = {
{
{0, 1, 2},
{10, 11, 12},
{20, 21, 22}
},
{
{100, 101, 102},
{110, 111, 112},
{120, 121, 122}
},
{
{200, 201, 202},
{210, 211, 212},
{220, 221, 222}
},
{
{300, 301, 302},
{310, 311, 312},
{320, 321, 322}
},
{
{400, 401, 402},
{410, 411, 412},
{420, 421, 422}
},
{
{500, 501, 502},
{510, 511, 512},
{520, 521, 522}
},
{
{600, 601, 602},
{610, 611, 612},
{620, 621, 622}
},
{
{700, 701, 702},
{710, 711, 712},
{720, 721, 722}
},
{
{800, 801, 802},
{810, 811, 812},
{820, 821, 822}
}
};
int[][] arrayConvt;
/*****
* What should go here to fill out `arrayConvt` using entries from `array` so it's equivalent to `array2d` below?
*/
int[][] array2d = {
{ 0, 1 , 2, 100, 101, 102, 200, 201, 202},
{ 10, 11, 12, 110, 111, 112, 210, 211, 212},
{ 20, 21, 22, 120, 121, 122, 220, 221, 222},
{300, 301, 302, 400, 401, 402, 500, 501, 502},
{310, 311, 312, 410, 411, 412, 510, 511, 512},
{320, 321, 322, 420, 421, 422, 520, 521, 522},
{600, 601, 602, 700, 701, 702, 800, 801, 802},
{610, 611, 612, 710, 711, 712, 810, 811, 812},
{620, 621, 622, 720, 721, 722, 820, 821, 822}
};
}
Try this.尝试这个。
public static void main(String[] args) {
int[][][] array = {
{{0, 1, 2}, {3, 4, 5}, {6, 7, 8}},
{{10, 11, 12}, {13, 14, 15}, {16, 17, 18}},
{{20, 21, 22}, {23, 24, 25}, {26, 27, 28}},
{{30, 31, 32}, {33, 34, 35}, {36, 37, 38}},
{{40, 41, 42}, {43, 44, 45}, {46, 47, 48}},
{{50, 51, 52}, {53, 54, 55}, {56, 57, 58}},
{{60, 61, 62}, {63, 64, 65}, {66, 67, 68}},
{{70, 71, 72}, {73, 74, 75}, {76, 77, 78}},
{{80, 81, 82}, {83, 84, 85}, {86, 87, 88}},
};
int[][] arrayConv = new int[9][9];
int[][] s = {
{0, 0}, {0, 3}, {0, 6},
{3, 0}, {3, 3}, {3, 6},
{6, 0}, {6, 3}, {6, 6},
};
for (int i = 0, p = 0; i < 9; ++i, ++p)
for (int j = 0, r = s[p][0]; j < 3; ++j, ++r)
for (int k = 0, c = s[p][1]; k < 3; ++k, ++c)
arrayConv[r][c] = array[i][j][k];
for (int[] r : arrayConv)
System.out.println(Arrays.toString(r));
}
output:输出:
[0, 1, 2, 10, 11, 12, 20, 21, 22]
[3, 4, 5, 13, 14, 15, 23, 24, 25]
[6, 7, 8, 16, 17, 18, 26, 27, 28]
[30, 31, 32, 40, 41, 42, 50, 51, 52]
[33, 34, 35, 43, 44, 45, 53, 54, 55]
[36, 37, 38, 46, 47, 48, 56, 57, 58]
[60, 61, 62, 70, 71, 72, 80, 81, 82]
[63, 64, 65, 73, 74, 75, 83, 84, 85]
[66, 67, 68, 76, 77, 78, 86, 87, 88]
First, construct some source data首先,构造一些源数据
int src[][][] = new int[9][3][3];
for (int r = 0; r < 9; r++) {
for (int rr = 0; rr < 3; rr++) {
for (int cc = 0; cc < 3; cc++) {
src[r][rr][cc] = r * 9 + rr * 3 + cc + 1;
}
}
}
for (int[][] d : src) {
System.out.println(Arrays.deepToString(d));
}
prints印刷
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
[[10, 11, 12], [13, 14, 15], [16, 17, 18]]
[[19, 20, 21], [22, 23, 24], [25, 26, 27]]
[[28, 29, 30], [31, 32, 33], [34, 35, 36]]
[[37, 38, 39], [40, 41, 42], [43, 44, 45]]
[[46, 47, 48], [49, 50, 51], [52, 53, 54]]
[[55, 56, 57], [58, 59, 60], [61, 62, 63]]
[[64, 65, 66], [67, 68, 69], [70, 71, 72]]
[[73, 74, 75], [76, 77, 78], [79, 80, 81]]
Now transform the matrix现在变换矩阵
int[][] dst = transform(src);
for (int[] row : dst) {
System.out.println(Arrays.toString(row));
}
prints印刷
[1, 2, 3, 10, 11, 12, 19, 20, 21]
[4, 5, 6, 13, 14, 15, 22, 23, 24]
[7, 8, 9, 16, 17, 18, 25, 26, 27]
[28, 29, 30, 37, 38, 39, 46, 47, 48]
[31, 32, 33, 40, 41, 42, 49, 50, 51]
[34, 35, 36, 43, 44, 45, 52, 53, 54]
[55, 56, 57, 64, 65, 66, 73, 74, 75]
[58, 59, 60, 67, 68, 69, 76, 77, 78]
[61, 62, 63, 70, 71, 72, 79, 80, 81]
public static int[][] transform(int[][][] src) {
int sr = 0;
int[][] dst = new int[9][9];
for (int x = 0; x < 3; x++) {
for (int sc = 0; sc < 3; sc++) {
int r = x * 3 + sc;
System.arraycopy(src[sr][sc], 0, dst[r], 0, 3);
System.arraycopy(src[sr + 1][sc], 0, dst[r], 3, 3);
System.arraycopy(src[sr + 2][sc], 0, dst[r], 6, 3);
}
sr = sr + 3;
}
return dst;
}
The best way of figuring out how to do this sort of thing is to play around with indices & reshaping, examining the resultant arrays.弄清楚如何做这种事情的最好方法是使用索引和重塑,检查结果数组。 Once you do this, you notice a few things that can help you come up with more formal approaches.
一旦你这样做了,你就会注意到一些可以帮助你想出更正式方法的事情。
One is to examine the mapping in terms of array index expressions.一种是根据数组索引表达式检查映射。 Since you want to map
array[i][j][k]
to arrayConvt[u][v]
, you need a way of expressing u
and v
in terms of i
, j
and k
(or vice versa).由于您想将
array[i][j][k]
arrayConvt[u][v]
到arrayConvt[u][v]
,您需要一种根据i
、 j
和k
来表达u
和v
的方法(反之亦然)。
Let's start with u
.让我们从
u
开始。 Note each array[i][j]
remains contiguous in the result.注意每个
array[i][j]
在结果中保持连续。 Note also that array[i][j]
is followed by array[i+1][j]
(rather than array[i][j+1]
) until you reach the end of arrayConvt
.另请注意,
array[i][j]
后跟array[i+1][j]
(而不是array[i][j+1]
),直到到达arrayConvt
。 Thus, array[i..i+2][j]
(where i
is a multiple of 3), if flattened, becomes arrayConvt[j+x]
.因此,
array[i..i+2][j]
(其中i
是 3 的倍数),如果展平,则变为arrayConvt[j+x]
。 The x
is present because the range of j
doesn't quite match between array
and arrayConvt
, and so an adjustment is needed. x
存在是因为j
的范围在array
和arrayConvt
之间不太匹配,因此需要进行调整。 Once the first 3 arrays in arrayConvt
are filled, j
goes back to 0, but j+x
can go on to the next element of arrayConvt
.一旦
arrayConvt
中的前 3 个数组被填充, j
返回到 0,但j+x
可以继续到arrayConvt
的下一个元素。 As for where to get x
, k
is similarly limited in range, but i
hasn't run through its range.至于从哪里得到
x
, k
范围同样有限,但i
还没有跑过它的范围。 Since j
runs 0..2, it only needs to be combined with a multiple of 3, which we can get with (i / 3) * 3
.由于
j
运行 0..2,它只需要与 3 的倍数组合,我们可以用(i / 3) * 3
。 This gives j + (i / 3)*3
, which a quick mental check will show that it runs 0..8.这给出了
j + (i / 3)*3
,快速的心理检查将显示它运行 0..8。 Thus, u = j + (i / 3) * 3
.因此,
u = j + (i / 3) * 3
。
On to v
.到
v
。 First note:第一个注意:
k
) in array[i][j][k]
changes just as rapidly for arrayConvt
and array[i][j][k]
的次要索引 ( k
) 的变化与arrayConvt
和arrayConvt
is independent of j
arrayConvt
的次要索引独立于j
Thus v = k + f(i)
(where f
must be determined).因此
v = k + f(i)
(其中f
必须确定)。 Looking at how each arrayConvt[u]
is layed out in terms of k
and the 1D arrays from array[i][j]
( <1D> #n
in the diagram), we see something similar to how u
related to i
.查看每个
arrayConvt[u]
如何根据k
和来自array[i][j]
的一维数组(图中的<1D> #n
)进行<1D> #n
,我们看到类似于u
如何与i
相关的内容。
v | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
k | 0 | 1 | 2 | 0 | 1 | 2 | 0 | 1 | 2 |
| <1D> #0 | <1D> #1 | <1D> #2 |
i | 3a + 0 | 3a + 1 | 3a + 2 |
f(i) | 0 | 3 | 6 |
We can see that for any row of arrayConvt
, i % 3
will range over 0..2.我们可以看到,对于
arrayConvt
任何行, i % 3
范围将超过 0..2。 (i % 3) * 3
gives us f(i)
. (i % 3) * 3
给我们f(i)
。 Thus v = k + (i % 3) * 3
因此
v = k + (i % 3) * 3
This gives you a loop over the source array indices, which are mapped to the destination array indices.这为您提供了对映射到目标数组索引的源数组索引的循环。
int[][] arrayConvt = array[array.length][array[0].length * array[0][0].length];
for (int i = 0; i < array.length; ++i) {
for (int j = 0; j < array[i].length; ++j) {
for (int k = 0; k < array[i][j].length; ++j) {
arrayConvt[j + (i/3)*3][k + (i%3)*3] = array[i][j][k];
}
}
}
You can take the above expressions for u
and v
and rewrite them so i
, j
and k
are in terms of u
and v
.您可以将上述
u
和v
表达式重写为i
、 j
和k
以u
和v
。 You could also try starting from u
and v
and examine how i
, j
and k
might come from them.您也可以尝试从
u
和v
并检查i
、 j
和k
可能来自它们的方式。 Let's do this, but by a different route: examine the entries in the sample array2d
, since i
, j
and k
can be read directly from it (not an accident; by encoding coordinates into the original array and figuring out where each element should get mapped to, the overall mapping is, in effect, created. You could even use this as the basis for the mapping function: loop over the elements of the coordinate array, and use the values & indices to copy from the source to the destination).让我们这样做,但通过不同的途径:检查样本
array2d
的条目,因为可以直接从中读取i
、 j
和k
(不是偶然的;通过将坐标编码到原始数组中并找出每个元素应该得到的位置映射到,整个映射实际上已创建。您甚至可以将其用作映射函数的基础:遍历坐标数组的元素,并使用值和索引从源复制到目标) .
k
we see increasing left-to-right only (along v
), though it wraps around. k
我们只看到从左到右增加(沿着v
),尽管它环绕。 This is simply v % 3
.这只是
v % 3
。 j
increases top-to-bottom (along u
) and also wraps around. j
从上到下(沿u
)增加并环绕。 Thus j = u % 3
.因此
j = u % 3
。
i
varies with both u
and v
. i
随u
和v
。 It also occurs in groups of 3 along both axes before changing, so we're looking for something involving u / 3
and v / 3
.它也在改变之前沿两个轴以 3 个为一组出现,因此我们正在寻找涉及
u / 3
和v / 3
。 Lastly, it varies faster along v
and jumps by 3 along u
, so i = (u / 3) * 3 + (v / 3)
.最后,它沿
v
变化更快,沿u
跳跃 3,因此i = (u / 3) * 3 + (v / 3)
。
You can loop over the destination array indices, and map the source array indices.您可以遍历目标数组索引,并映射源数组索引。
int[][] arrayConvt = array[array.length][array[0].length * array[0][0].length];
for (int u = 0; i < arrayConvt.length; ++i) {
for (int v = 0; j < arrayConvt[i].length; ++j) {
arrayConvt[u][v] = array[ (u / 3) * 3 + (v / 3) ][u % 3][v % 3];
}
}
There's another approach that, once spotted, is even easier to work with.还有另一种方法,一旦发现,就更容易使用。 Hidden in the 3D
array
is a hypercube: array
can be viewed as a projection of a 4D array into 3 dimensions.隐藏在 3D
array
是一个超立方体: array
可以被视为 4D 阵列到 3 维的投影。 You can realize this in various (equivalent) ways:您可以通过各种(等效)方式实现这一点:
array
as 9x3x3, broken into three cubes, you get one fairly common visualization of a projected discrete hypercube (the same as a 3x3x3 discrete cube projected into 2D is 3 3x3 squares).array
设想为 9x3x3,分成三个立方体,您会得到一个相当常见的投影离散超立方体的可视化(与投影到 2D 的 3x3x3 离散立方体是 3 个 3x3 正方形相同)。M*N
by mapping [i][j]
to i*N+j
(this is how multidimensional arrays are implemented in languages that use contiguous memory for such arrays).[i][j]
映射到i*N+j
可以将 MxN 数组表示为大小为M*N
的 1 个较低等级的数组(这就是在对此类数组使用连续内存的语言中实现多维数组的方式) . Under this mapping, a T[M][N]
is equivalent to T[M*N]
.T[M][N]
等价于T[M*N]
。 Looking at the indices, note that i
can be refactored as i = i_0 * 3 + i_1
, where i_0
and i_1
range from 0 through 2. Thus, array[9][3][3]
is equivalent to a multidimensional array array4d[3][3][3][3]
.i
可以重构为i = i_0 * 3 + i_1
,其中i_0
和i_1
范围从 0 到 2。因此, array[9][3][3]
等效于多维数组array4d[3][3][3][3]
。 From this vantage, the problem is a simple reshaping from a rank 4 cube to a rank 2 cube;从这个角度来看,问题是从 4 阶立方体到 2 阶立方体的简单重塑; the main work is:
主要工作是:
With indices h
, i
, j
and k
, we have the index expression array[h*3+i][j][k]
(note: i
is the 3rd dimension, or depth, and h
is the 4th, or duration).使用索引
h
、 i
、 j
和k
,我们有索引表达式array[h*3+i][j][k]
(注意: i
是第 3 维或深度, h
是第 4 维或持续时间) . When mapping, the last index of array
remains the last of arrayConvt
(the 1st dimension).映射时,
array
的最后一个索引仍然是arrayConvt
的最后一个(第一维)。 After completing a loop over k
, we advance along the outermost array;在
k
完成一个循环后,我们沿着最外面的数组前进; in particular, the 3rd dimension, i
(the 4th is also along the outermost array but jumps from cube to cube).特别是第 3 维,
i
(第 4 维也沿着最外面的数组,但从一个立方体跳到另一个立方体)。 After copying a square (with dimensions width x depth), we continue with a cube, travelling along its height, or j
axis.在复制一个正方形(尺寸为宽 x 深)之后,我们继续一个立方体,沿着它的高度或
j
轴移动。 Lastly, we check that the travel direction corresponds to the remaining axis: after finishing a cube, we go to the next cube, which is indeed along h
.最后,我们检查行进方向是否对应于剩余的轴:完成一个立方体后,我们去下一个立方体,它确实沿着
h
。 This gives a an index order (minor to major) of k
, i
, j
, h
.这给出了
k
、 i
、 j
、 h
的索引顺序(次要到主要)。
The formulae for u
and v
come straight from the T[M][N]
to T[M*N]
conversion. u
和v
的公式直接来自T[M][N]
到T[M*N]
转换。 Each index of arrayConvt
uses two indices from the hypercube, in the previously determined index order: that's h
and j
for u
, and i
and k
for v
. arrayConvt
每个索引arrayConvt
使用超立方体中的两个索引,按照先前确定的索引顺序:即u
的h
和j
,以及v
i
和k
。 Thus, u = h * 3 + j
and v = i * 3 + k
.因此,
u = h * 3 + j
和v = i * 3 + k
。
int M = 3,
N = 3,
P = 3,
Q = 3;
for (int h = 0; h < M; ++h) {
for (int i = 0; i < N; ++i) {
for (int j = 0; j < P; ++j) {
for (int k = 0; k < Q; ++j) {
arrayConvt[h * 3 + j][i * 3 + k] = array[h * 3 + i][j][k];
}
}
}
}
Note the index expressions here can be converted to the ones used earlier.请注意,此处的索引表达式可以转换为之前使用的索引表达式。 You could use this to write a non-nested loop over 0..80 that reshapes
array
, but it wouldn't be as readable.您可以使用它来编写一个超过 0..80 的非嵌套循环来重塑
array
,但它不会那么可读。 You can also use this approach to reshape the hypercube to any compatible shape you want.您还可以使用这种方法将超立方体重塑为您想要的任何兼容形状。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.