将多维数组转换为一维数组的算法

Posted

技术标签:

【中文标题】将多维数组转换为一维数组的算法【英文标题】:Algorithm to convert a multi-dimensional array to a one-dimensional array 【发布时间】:2011-04-06 12:28:16 【问题描述】:

将二维数组转换为一维数组很容易,但是如何将二维以上的多维数组转换为一维数组呢?例如,假设我有 int [5][5][5] x 和 int [125] y,我想将 x[3][4][2] 的值放在 y 中的正确位置?

希望这是有道理的。

【问题讨论】:

【参考方案1】:

实际上有一种非常酷的方式来思考这个问题,但还没有人在这里发布过。

在最简单的情况下,您可以将 X、Y、Z 坐标想象为您创建的虚数系统中的数字。这些数字写成 XYZ,因此您的示例 [3][4][2] 将写为:342

我们这些习惯于用八进制和十六进制思考的人习惯于认为这并不意味着三百、四个十和两个一,而是

三个 64、四个 8 和两个 1

三个 256、四个 16 和两个 1

这确实是您的虚数系统需要做的,但是每个数字都是数组中相应边的长度的底数,乘以下一个较低的底数(除非没有,在这种情况下,1。此计算中不使用最后一个数组长度,而只是为了限制您的循环。此计算中的排序基于您希望如何将边长转换为线性元素。

对于 5x5x5 数组,这很简单:

25 秒 | 5秒 | 1s * 3 | 4 | 2 ----+----+--- 75 + 20 + 2 = 97

其他基础可能更复杂,尤其是尺寸不均匀的情况下,但这只是考虑问题的另一种方式。

这是一个非统一的 565 示例:

30 多岁 | 5秒 | 1s * 3 | 4 | 2 ----+----+--- 90 + 20 + 2 = 102

【讨论】:

【参考方案2】:

您可以在 C# 中执行以下操作。

public class ArrayIndexer

    private readonly int[] _bounds;
    private readonly int[] _sum;

    public ArrayIndexer(params int[] bounds)
    
        _bounds = bounds;

        // Pre-compute bounds sums for speed.
        _sum = new int[bounds.Length - 1];
        for (int i = 1, sum = _bounds[i - 1]; i < _bounds.Length; ++i, sum *= _bounds[i - 1])
            _sum[i-1] = sum;
    

    public T Index<T>(T[] array, params int[] indices)
    
        if (indices.Length != _bounds.Length)
            throw new ArgumentException("There should be as many indices as bounds", "indices");

        var index = indices[0];
        for (int i = 1, sum = _bounds[i - 1]; i < indices.Length; ++i, sum *= _bounds[i - 1])
            index += sum * indices[i];
        return array[index];
    

    public T FastIndex<T>(T[] array, params int[] indices)
    
        if (indices.Length != _bounds.Length)
            throw new ArgumentException("There should be as many indices as bounds", "indices");

        var index = indices[0];
        for (int i = 1; i < indices.Length; ++i)
            index += _sum[i-1] * indices[i];
        return array[index];
    

或者转化为n维数组。

public static class ArrayExtensions

    public static Array CreateArray<T>(this T[] array1d, params int[] bounds)
    
        var arrayNd = Array.CreateInstance(typeof(T), bounds);

        var indices = new int[bounds.Length];
        for (var i = 0; i < array1d.Length; ++i)
        
            arrayNd.SetValue(array1d[i], indices);

            for (int j = 0; j < bounds.Length; ++j)
            
                if (++indices[j] < bounds[j])
                    break;
                indices[j] = 0;
            
        

        return arrayNd;
    

然后进行测试。

int[] array3d =
    new[]
    
        0, 1, 2, 3,
        4, 5, 6, 7,
        8, 9, 10, 11,

        12, 13, 14, 15,
        16, 17, 18, 19,
        20, 21, 22, 23
    ;

var copied3d = (int[, ,])array3d.CreateArray(4, 3, 2);
var indexer3d = new ArrayIndexer(4, 3, 2);

for (int i = 0; i < 4; ++i)

    for (int j = 0; j < 3; ++j)
    
        for (int k = 0; k < 2; ++k)
        
            var x = indexer3d.FastIndex(array3d, i, j, k);
            var y = copied3d[i, j, k];
            Debug.Print("Array[0,1,2] = 3 and 4 match = 5", i, j, k, x, y, x == y);
        
    

【讨论】:

【参考方案3】:

这里已经有几个技术上不错的答案,但这里有一种更直观的理解方式......


好的,所以你知道如何从一维情况转到二维情况。

一维数组如下所示:

int [5] :

+-----+-----+-----+-----+-----+
|  0  |  1  |  2  |  3  |  4  |
|     |     |     |     |     |
+-----+-----+-----+-----+-----+

二维数组如下所示:

int [5][5] :

+-----+-----+-----+-----+-----+     
| 0,0 | 0,1 | 0,2 | 0,3 | 0,4 |     
|     |     |     |     |     |     
+-----+-----+-----+-----+-----+     
| 1,0 | 1,1 | 1,2 | 1,3 | 1,4 |     
|     |     |     |     |     |     
+-----+-----+-----+-----+-----+     
| 2,0 | 2,1 | 2,2 | 2,3 | 2,4 | 
|     |     |     |     |     |     
+-----+-----+-----+-----+-----+     
| 3,0 | 3,1 | 3,2 | 3,3 | 3,4 |     
|     |     |     |     |     |     
+-----+-----+-----+-----+-----+     
| 4,0 | 4,1 | 4,2 | 4,3 | 4,4 |     
|     |     |     |     |     |     
+-----+-----+-----+-----+-----+     

可以像这样描绘到相应一维数组的转换:

+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+- - -
| 0,0 | 0,1 | 0,2 | 0,3 | 0,4 | 1,0 | 1,1 | 1,2 | 1,3 | 1,4 | etc.
|     |     |     |     |     |     |     |     |     |     |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+- - -
                             vvv
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+- - -
|  0  |  1  |  2  |  3  |  4  |  5  |  6  |  7  |  8  |  9  | etc.
|     |     |     |     |     |     |     |     |     |     |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+- - -

但另一种思考方式是描绘原始数组,但重新标记 - 像这样:

int [5][5] :

+-----+-----+-----+-----+-----+     +-----+-----+-----+-----+-----+
| 0,0 | 0,1 | 0,2 | 0,3 | 0,4 |     |  0  |  1  |  2  |  3  |  4  |
|     |     |     |     |     |     |     |     |     |     |     |
+-----+-----+-----+-----+-----+     +-----+-----+-----+-----+-----+
| 1,0 | 1,1 | 1,2 | 1,3 | 1,4 |     |  5  |  6  |  7  |  8  |  9  |
|     |     |     |     |     |     |     |     |     |     |     |
+-----+-----+-----+-----+-----+     +-----+-----+-----+-----+-----+
| 2,0 | 2,1 | 2,2 | 2,3 | 2,4 | =>  | 10  | 11  | 12  | 13  | 14  |
|     |     |     |     |     |     |     |     |     |     |     |
+-----+-----+-----+-----+-----+     +-----+-----+-----+-----+-----+
| 3,0 | 3,1 | 3,2 | 3,3 | 3,4 |     | 15  | 16  | 17  | 18  | 19  |
|     |     |     |     |     |     |     |     |     |     |     |
+-----+-----+-----+-----+-----+     +-----+-----+-----+-----+-----+
| 4,0 | 4,1 | 4,2 | 4,3 | 4,4 |     | 20  | 21  | 22  | 23  | 24  |
|     |     |     |     |     |     |     |     |     |     |     |
+-----+-----+-----+-----+-----+     +-----+-----+-----+-----+-----+

2-D array index [i][j]          =>  1-D array index [i*5 + j]

...如果你这样想,3 维的情况也遵循同样的原则(更高维度的情况也是如此——它变得越来越难以可视化!):

int [5][5][5] :

+-----+-----+-----+-----+-----+         +-----+-----+-----+-----+-----+
|+-----+-----+-----+-----+-----+        |+-----+-----+-----+-----+-----+
||+-----+-----+-----+-----+-----+       ||+-----+-----+-----+-----+-----+
|||+-----+-----+-----+-----+-----+      |||+-----+-----+-----+-----+-----+
||||1,0,0|1,0,1|1,0,2|1,0,3|1,0,4|      |||| 25  | 26  | 27  | 28  | 29  |
||||   +-----+-----+-----+-----+-----+  ||||   +-----+-----+-----+-----+-----+
|||+---|0,0,0|0,0,1|0,0,2|0,0,3|0,0,4|  |||+---|  0  |  1  |  2  |  3  |  4  |
||||1,1|     |     |     |     |     |  |||| 30|     |     |     |     |     |
||||   +-----+-----+-----+-----+-----+  ||||   +-----+-----+-----+-----+-----+
|||+---|0,1,0|0,1,1|0,1,2|0,1,3|0,1,4|  |||+---|  5  |  6  |  7  |  8  |  9  |
||||1,2|     |     |     |     |     |  |||| 35|     |     |     |     |     |
||||   +-----+-----+-----+-----+-----+  ||||   +-----+-----+-----+-----+-----+
|||+---|0,2,0|0,2,1|0,2,2|0,2,3|0,2,4|=>|||+---| 10  | 11  | 12  | 13  | 14  |
||||1,3|     |     |     |     |     |  |||| 40|     |     |     |     |     |
||||   +-----+-----+-----+-----+-----+  ||||   +-----+-----+-----+-----+-----+
+||+---|0,3,0|0,3,1|0,3,2|0,3,3|0,3,4|  +||+---| 15  | 16  | 17  | 18  | 19  |
 +||1,4|     |     |     |     |     |   +|| 45|     |     |     |     |     |
  +|   +-----+-----+-----+-----+-----+    +|   +-----+-----+-----+-----+-----+
   +---|0,4,0|0,4,1|0,4,2|0,4,3|0,4,4|     +---| 20  | 21  | 22  | 23  | 24  |
       |     |     |     |     |     |         |     |     |     |     |     |
       +-----+-----+-----+-----+-----+         +-----+-----+-----+-----+-----+

3-D array index [i][j][k]             =>  1-D array index [i*5*5 + j*5 + k]

【讨论】:

谢谢!很好的方式来说明它! 有关 int[dimX][dimY][dimZ] 的更多详细信息:一维数组索引 [i * dimY*dimZ + j * dimZ + k] 这个例子启发了我理解多项式方程和数组(向量)之间的关系。【参考方案4】:

您可以有不同的方法将多维数组映射到线性数组。问题是你必须选择一个约定。让我们遵循以下约定。第一个索引指定一个块容器,第二个指定前一个容器中的一个块,最后第三个索引是块内的偏移量。您可以轻松地将其概括为多维,但在此示例中将其保持为 3:

#include <cstddef>

std::size_t linear_index
    (std::size_t f,
     std::size_t s, 
     std::size_t t,
     std::size_t f_width,
     std::size_t s_width)

    return (f*f_width + s)*s_width + t;

【讨论】:

【参考方案5】:
m0,m1,.. are dimensions
A(i,j,k,...) -> A0[i + j*m0 + k*m0*m1 + ...]

和有用的 C 技巧:

double *A;
size_t m;
#define A(i,j) A[(i) + (j)*m];

【讨论】:

以上是关于将多维数组转换为一维数组的算法的主要内容,如果未能解决你的问题,请参考以下文章

thinkphp怎么将多维数组变成一维数组

php PHP array_flatten()函数。将多维数组转换为一维数组。

JavaScript学习(八十一)—将多维数组转化为一维数组

php中的二维多维数组到一维数组[重复]

扁平化数组,多维数组变一维数组

表示为一维的多维数组(模板化为 n 维)