为什么我们既有锯齿数组又有多维数组?

124
  1. 什么是交错数组和多维数组的区别?它们之间有什么优缺点吗?

  2. 为什么Visual Studio不允许我进行某些操作?

MyClass[][] abc = new MyClass[10][20];

(我们以前在 C++ 中这样做,但是在 C# 中,[20] 下划线标记为红色的波浪线。显示无效的秩指定符)

但是对此感到满意。

MyClass[,] abc = new MyClass[10,20];
最后,我该如何以单行方式初始化这个数组(就像我们使用{new xxx...}{new xxx....}初始化简单的数组一样)?
MyClass[][,][,] itemscollection;

16
嵌套数组的关键在于,“嵌套”的数组不需要具有相同的大小。 - Ani
1
根据文档,多维数组语法[X,Y]是有效的。 - ndtreviv
附加子问题:是否可以在多维数组中使用foreach()? - Serge Wautier
@Serge - 当然,因为Array实现了IEnumerable。你可以尝试一下,亲自验证一下 :) - thecoop
这个回答解决了你的问题吗?C#中多维数组和数组的区别是什么? - Walter
13个回答

140
  1. 嵌套数组是一种数组的数组,因此int[][]是一个int[]数组,每个数组可以有不同的长度并占据自己的内存块。而多维数组(int[,])则是单一的内存块(本质上就是一个矩阵)。

  2. 你无法创建MyClass[10][20]数组,因为每个子数组必须要分别初始化,因为它们是独立的对象:

  3. MyClass[][] abc = new MyClass[10][];
    
    for (int i=0; i<abc.Length; i++) {
        abc[i] = new MyClass[20];
    }
    

    一个 MyClass[10,20] 是可以的,因为它将单个对象初始化为一个有10行和20列的矩阵。

  4. 一个 MyClass[][,][,] 可以这样初始化(尽管未经编译测试):

    MyClass[][,][,] abc = new MyClass[10][,][,];
    
    for (int i=0; i<abc.Length; i++) {
        abc[i] = new MyClass[20,30][,];
    
        for (int j=0; j<abc[i].GetLength(0); j++) {
            for (int k=0; k<abc[i].GetLength(1); k++) {
                abc[i][j,k] = new MyClass[40,50];
            }
        }
    }
    
    记住,CLR 对单维数组的访问进行了大量优化,因此使用锯齿数组很可能比相同大小的多维数组更快。

11
您能否指出一些证据表明单维数组访问更快? - GreyCloud
9
多维数组和数组的数组在C语言中有什么区别? - thecoop
多维数组有常见的使用情况吗? - ryanwebjackson
2
示例:棋盘 var board = new Piece[8, 8];,变换矩阵 var m = new double[2, 2]; - Olivier Jacot-Descombes

49

嵌套数组是由多个数组组成的,每个数组的大小不一定相同。你可以有这样的结构

int[][] jaggedArray = new int[5][];
jaggedArray[0] = new[] {1, 2, 3}; // 3 item array
jaggedArray[1] = new int[10];     // 10 item array
// etc.

它是一组相关的数组。

另一方面,多维数组更像是一个紧密的分组,例如盒子、表格、立方体等,其中没有不规则长度。也就是说:

int i = array[1,10];
int j = array[2,10]; // 10 will be available at 2 if available at 1

我尝试了你的代码,但它无法编译。请尝试添加 int[3],然后使用以下代码:jaggedArray[0] = int[3]{ 1, 2, 3 }; - barlop
我知道这已经过时了,但仅供信息目的,int[3]并不必要。一个简单的int[]就足够了。int[][] myArray = new int[5][]; myArray[0] = new int[] {1, 2, 3, 4}; 这就是所需的全部内容。 - Velocibadgery
你能让这个在C#中编译吗?除非我将jaggedArray [0] = {1,2,3};更改为= new [] {1,2,3}(或在C# 3.0之前= new int [] {1,2,3}),否则我无法编译它。根据微软的C#编程指南,“您可以声明一个数组变量而不创建它,但是当您将新数组分配给此变量时,必须使用new运算符。” - Joel V. Earnest-DeYoung

13

矩形数组的每一行总是有相同数量的列。

MyClass[,] x = new MyClass[10,30]

每一行都有30个列,而在锯齿数组中则不需要这样。因此,我认为你需要单独初始化锯齿数组中的每一行:

MyClass[][] x = new MyClass[10][];

for(int i = 0; i < 10; i++)
{
    x[i] = new MyClass[30];
}

实际上,这意味着不是每一行的不规则数组都必须包含相同数量的元素。 (在我的示例中,它确实具有相同数量的元素,但这不是必需的)。

例如,您完全可以这样做:

MyClass[][] x = new MyClass[10][];

for(int i = 0; i < 10; i++)
{
    x[i] = new MyClass[(30 + i)];
}

这篇文章可能对你有趣。


6

第三步) 要初始化像[][,][,]这样的怪物,你可以这样做:

        int [,][,] multiArr1 = { { new int[,] { { 2, 2 }, { 1, 1 } },
                                     new int[,] { { 2, 2 }, { 1, 1 } } },
                                     { new int[,] { { 2, 2 }, { 1, 1 } },
                                         new int[,] { { 2, 2 }, { 1, 1 } } } };
        int [,][,] multiArr2 = { { new int[,] { { 2, 2 }, { 1, 1 } },
                                     new int[,] { { 2, 2 }, { 1, 1 } } },
                                     { new int[,] { { 2, 2 }, { 1, 1 } },
                                         new int[,] { { 2, 2 }, { 1, 1 } } } };

        int [][,][,] superMultiArray = { multiArr1, multiArr2 };

2

多维数组是C#中的一个矩形数组。它每个维度只能有固定数量的元素。下面的代码示例展示了如何在C#中声明一个多维数组。

int[,] multiArray = new[3,3]

在C#中,锯齿数组是一种数组的数组。它可以包含不同大小的数组。下面的代码示例展示了如何在C#中声明一个锯齿数组。

int[][] jaggedArray = new int[3][];
            jaggedArray[0] = new int [1];
            jaggedArray[1] = new int[2];
            jaggedArray[2] = new int[3];

在上面的代码中,我们创建了大小为3的交错数组jaggedArray,这意味着jaggedArray是一个由3个数组组成的数组。这3个数组位于jaggedArray的索引0、1和2处。从示例中可以清楚地看出,所有这些数组的大小都不同。
在C#中,应该优先使用交错数组而不是传统的多维数组,因为它们更加灵活。例如,如果我们要存储一个人的爱好,首选的方法应该是使用交错数组,因为并不是每个人都有相同数量的爱好。对于兴趣爱好和许多其他事物也是如此。

1
如果您正在寻找一个具有设置边界的多维数组,请始终使用[,]样式语法。这将确保每个部分的大小相等。
当您使用[][]时,实际上正在创建一个数组的数组。这意味着每个数组的大小可以不同。例如:
int[][] jaggedArray = new int[5][]
for(int index = 0; index < jaggedArray.Length ; ++index)
{
    jaggedArray[index] = new int[index + 1];
}

1

内联声明看起来会像这样:

int[,] numbers = { {1, 2}, {3, 4}, {5, 6} };

1

关于 #1,参见 此 Stack Overflow 问题

关于嵌套或多维内联数组,请参阅编程指南

// Three-dimensional array.
int[, ,] array3D = new int[,,] { { { 1, 2, 3 }, { 4, 5, 6 } },
{ { 7, 8, 9 }, { 10, 11, 12 } } };

// Same array with dimensions specified at declaration.
int[, ,] array3Da = new int[2, 2, 3] { { { 1, 2, 3 }, { 4, 5, 6 } },
{ { 7, 8, 9 }, { 10, 11, 12 } } };

你不必指定维度(array3D),但如果你知道它们永远不会改变,了解你正在使用的维度(array3Da)是有帮助的。


1
对于多维数组,可以将其想象成一个箱子或矩形。每一行长度相同,每一列长度也相同。
在不规则数组中,行和列的大小可能不同。例如,列或行的大小可能不同。这会导致一个形状,可能不像矩形那样沿两侧是直线。相反,边缘可能是不规则的。
现在我用了2个维度/2个数组做例子,但这适用于更多情况。

0

我认为C#中的二维不规则数组内存分配类似于C++和C中的二维数组。 因为二维不规则数组具有指向指针数组的指针,每个指针都指向一个元素数组(例如整数元素);就像C++中的这段代码一样:

int** 2DArr {new int* [number1]};
for (int i = 0; i < number1; i++)
{
   2DArr[i] = new int[number2];
}

下面代码的内存分配与 C# 中的二维锯齿数组相同。但我还有疑问,如果我想错了,请您详细解释一下。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接