簡體   English   中英

將 3D 數組轉換為 2D 數組

[英]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 個塊的數組。 我想從左到右,從上到下重新組合塊:

9 x 3 x 3 陣列到 9 x 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]
  • sr,sc - 要復制的內部 3x3 矩陣的源行和列
  • r - 包含上述內容的目標行
  • 外循環用於創建目標行以及允許
    關鍵變量的中間增量
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] ,您需要一種根據ijk來表達uv的方法(反之亦然)。

計算目的地索引

讓我們從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的范圍在arrayarrayConvt之間不太匹配,因此需要進行調整。 一旦arrayConvt中的前 3 個數組被填充, j返回到 0,但j+x可以繼續到arrayConvt的下一個元素。 至於從哪里得到xk范圍同樣有限,但i還沒有跑過它的范圍。 由於j運行 0..2,它只需要與 3 的倍數組合,我們可以用(i / 3) * 3 這給出了j + (i / 3)*3 ,快速的心理檢查將顯示它運行 0..8。 因此, u = j + (i / 3) * 3

v 第一個注意:

  1. array[i][j][k]的次要索引 ( k ) 的變化與arrayConvt
  2. 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];
        }
    }
}

計算源索引

您可以將上述uv表達式重寫為ijkuv 您也可以嘗試從uv並檢查ijk可能來自它們的方式。 讓我們這樣做,但通過不同的途徑:檢查樣本array2d的條目,因為可以直接從中讀取ijk (不是偶然的;通過將坐標編碼到原始數組中並找出每個元素應該得到的位置映射到,整個映射實際上已創建。您甚至可以將其用作映射函數的基礎:遍歷坐標數組的元素,並使用值和索引從源復制到目標) .

k我們只看到從左到右增加(沿着v ),盡管它環繞。 這只是v % 3 j從上到下(沿u )增加並環繞。 因此j = u % 3

iuv 它也在改變之前沿兩個軸以 3 個為一組出現,因此我們正在尋找涉及u / 3v / 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_0i_1范圍從 0 到 2。因此, array[9][3][3]等效於多維數組array4d[3][3][3][3]

從這個角度來看,問題是從 4 階立方體到 2 階立方體的簡單重塑; 主要工作是:

  1. 從源中找出索引順序
  2. 確定要映射到的目的地索引

使用索引hijk ,我們有索引表達式array[h*3+i][j][k] (注意: i是第 3 維或深度, h是第 4 維或持續時間) . 映射時, array的最后一個索引仍然是arrayConvt的最后一個(第一維)。 k完成一個循環后,我們沿着最外面的數組前進; 特別是第 3 維, i (第 4 維也沿着最外面的數組,但從一個立方體跳到另一個立方體)。 在復制一個正方形(尺寸為寬 x 深)之后,我們繼續一個立方體,沿着它的高度或j軸移動。 最后,我們檢查行進方向是否對應於剩余的軸:完成一個立方體后,我們去下一個立方體,它確實沿着h 這給出了kijh的索引順序(次要到主要)。

uv的公式直接來自T[M][N]T[M*N]轉換。 arrayConvt每個索引arrayConvt使用超立方體中的兩個索引,按照先前確定的索引順序:即uhj ,以及v ik 因此, u = h * 3 + jv = 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM