[英]Convert 3D array to 2D array
我有一個秩為 3 的 int 數組array[9][3][3]
,我想通過刪除主軸(而不是中軸)將它轉換為一個秩為 2 的數組arrayConvt[9][9]
。 要制作 9x9 數組而不是 3x27,想象將array
分成 3 個相等的部分,每個部分在下一個之前布局到arrayConvt
。 請注意,中間數組 ( array[i]
) 在arrayConvt
不保持連續,但最里面的數組 ( array[i][j]
) 保持連續。
可視化它的一種方法是將array
視為 9 個塊的數組。 我想從左到右,從上到下重新組合塊:
如何根據此映射重塑array
?
下面的代碼示例提供了要使用的數據和所需的結果:
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}
};
}
嘗試這個。
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));
}
輸出:
[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]
首先,構造一些源數據
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));
}
印刷
[[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]]
現在變換矩陣
int[][] dst = transform(src);
for (int[] row : dst) {
System.out.println(Arrays.toString(row));
}
印刷
[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;
}
弄清楚如何做這種事情的最好方法是使用索引和重塑,檢查結果數組。 一旦你這樣做了,你就會注意到一些可以幫助你想出更正式方法的事情。
一種是根據數組索引表達式檢查映射。 由於您想將array[i][j][k]
arrayConvt[u][v]
到arrayConvt[u][v]
,您需要一種根據i
、 j
和k
來表達u
和v
的方法(反之亦然)。
讓我們從u
開始。 注意每個array[i][j]
在結果中保持連續。 另請注意, array[i][j]
后跟array[i+1][j]
(而不是array[i][j+1]
),直到到達arrayConvt
。 因此, array[i..i+2][j]
(其中i
是 3 的倍數),如果展平,則變為arrayConvt[j+x]
。 x
存在是因為j
的范圍在array
和arrayConvt
之間不太匹配,因此需要進行調整。 一旦arrayConvt
中的前 3 個數組被填充, j
返回到 0,但j+x
可以繼續到arrayConvt
的下一個元素。 至於從哪里得到x
, k
范圍同樣有限,但i
還沒有跑過它的范圍。 由於j
運行 0..2,它只需要與 3 的倍數組合,我們可以用(i / 3) * 3
。 這給出了j + (i / 3)*3
,快速的心理檢查將顯示它運行 0..8。 因此, u = j + (i / 3) * 3
。
到v
。 第一個注意:
array[i][j][k]
的次要索引 ( k
) 的變化與arrayConvt
和arrayConvt
的次要索引獨立於j
因此v = k + f(i)
(其中f
必須確定)。 查看每個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 |
我們可以看到,對於arrayConvt
任何行, i % 3
范圍將超過 0..2。 (i % 3) * 3
給我們f(i)
。 因此v = k + (i % 3) * 3
這為您提供了對映射到目標數組索引的源數組索引的循環。
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];
}
}
}
您可以將上述u
和v
表達式重寫為i
、 j
和k
以u
和v
。 您也可以嘗試從u
和v
並檢查i
、 j
和k
可能來自它們的方式。 讓我們這樣做,但通過不同的途徑:檢查樣本array2d
的條目,因為可以直接從中讀取i
、 j
和k
(不是偶然的;通過將坐標編碼到原始數組中並找出每個元素應該得到的位置映射到,整個映射實際上已創建。您甚至可以將其用作映射函數的基礎:遍歷坐標數組的元素,並使用值和索引從源復制到目標) .
k
我們只看到從左到右增加(沿着v
),盡管它環繞。 這只是v % 3
。 j
從上到下(沿u
)增加並環繞。 因此j = u % 3
。
i
隨u
和v
。 它也在改變之前沿兩個軸以 3 個為一組出現,因此我們正在尋找涉及u / 3
和v / 3
。 最后,它沿v
變化更快,沿u
跳躍 3,因此i = (u / 3) * 3 + (v / 3)
。
您可以遍歷目標數組索引,並映射源數組索引。
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];
}
}
還有另一種方法,一旦發現,就更容易使用。 隱藏在 3D array
是一個超立方體: array
可以被視為 4D 陣列到 3 維的投影。 您可以通過各種(等效)方式實現這一點:
array
設想為 9x3x3,分成三個立方體,您會得到一個相當常見的投影離散超立方體的可視化(與投影到 2D 的 3x3x3 離散立方體是 3 個 3x3 正方形相同)。[i][j]
映射到i*N+j
可以將 MxN 數組表示為大小為M*N
的 1 個較低等級的數組(這就是在對此類數組使用連續內存的語言中實現多維數組的方式) . 在此映射下, T[M][N]
等價於T[M*N]
。 查看索引,請注意i
可以重構為i = i_0 * 3 + i_1
,其中i_0
和i_1
范圍從 0 到 2。因此, array[9][3][3]
等效於多維數組array4d[3][3][3][3]
。從這個角度來看,問題是從 4 階立方體到 2 階立方體的簡單重塑; 主要工作是:
使用索引h
、 i
、 j
和k
,我們有索引表達式array[h*3+i][j][k]
(注意: i
是第 3 維或深度, h
是第 4 維或持續時間) . 映射時, array
的最后一個索引仍然是arrayConvt
的最后一個(第一維)。 在k
完成一個循環后,我們沿着最外面的數組前進; 特別是第 3 維, i
(第 4 維也沿着最外面的數組,但從一個立方體跳到另一個立方體)。 在復制一個正方形(尺寸為寬 x 深)之后,我們繼續一個立方體,沿着它的高度或j
軸移動。 最后,我們檢查行進方向是否對應於剩余的軸:完成一個立方體后,我們去下一個立方體,它確實沿着h
。 這給出了k
、 i
、 j
、 h
的索引順序(次要到主要)。
u
和v
的公式直接來自T[M][N]
到T[M*N]
轉換。 arrayConvt
每個索引arrayConvt
使用超立方體中的兩個索引,按照先前確定的索引順序:即u
的h
和j
,以及v
i
和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];
}
}
}
}
請注意,此處的索引表達式可以轉換為之前使用的索引表達式。 您可以使用它來編寫一個超過 0..80 的非嵌套循環來重塑array
,但它不會那么可讀。 您還可以使用這種方法將超立方體重塑為您想要的任何兼容形狀。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.