Pluralsight Logo
Author avatar

Pavneet Singh

Author badge Author

Multi-dimensional and Jagged Arrays

Pavneet Singh

Author BadgeAuthor
  • Oct 15, 2018
  • 10 Min read
  • 33 Views
  • Oct 15, 2018
  • 10 Min read
  • 33 Views
C#
Array

Introduction

Multi-dimensional arrays are an extended form of one-dimensional arrays and are frequently used to store data for mathematic computations, image processing, and record management. For example, a normal chess board has 8 rows and 8 columns which can be easily represented using a multi-dimensional array with size 8 by 8 (8 rows, each with the capacity to store 8 elements). This guide elaborates the variants of multi-dimensional arrays and its applications in C#.

An array is a collection of homogeneous data in a linear form, known as a one/single dimensional array. In other words, a one-dimensional array is a single row of similar data.

1
char[] one_d_array = {'A', 'B', 'C', 'D'};

Single dimensional arrays can only store a single series of data like

  • Series of roll numbers
  • Series of radio channel frequencies
  • Number of units sold every day

Often, you’ll be required to handle complex data stored in the form of a matrix or table for:

  • Pixel matrix of an image
  • Computer graphic transformation matrix
  • Adjacency matrix in graph theory to represent the connectivity of a node (Dijkstra adjacency matrix)

table2oneDarrayMapping

In the example above, every data row in the table can be mapped into a one-dimensional array.

Data from a matrix can also be stored in similar fashion.

2dMatrixindices

As shown in the above figure, this can be simplified by creating an array-type container (an array of arrays) which will keep the reference of other one-dimensional arrays, known as multi-dimensional arrays.

1
2
3
4
string[,] stuTable = new string[,]{
     { "Tom"  , "35", "USA" },
     { "Sam"  , "38", "Australia" },
     { "Henry", "40", "England" } };

Requirement: Follow the Deep Dive into Array Basics guide which thoroughly explains one-dimensional arrays and related concepts.

Multi-dimensional Arrays

A multi-dimensional array is a collection of one-dimensional arrays and can represent relational tables and matrices. Both matrices and tables can be seen as a collection of rows that can be mapped into an array of rows (a one-dimensional array). Multi-dimensional arrays store values in row-major order, meaning that elements of all rows are stored in a consecutive (one row after the another) manner. A real-life example of multi-dimensional arrays would be the total number of units sold every day, of every week in a month at a store.

1
2
3
4
int[,] sales = new int[,]{
     {10, 20, 12, 15, 15, 27, 35},
     {9, 14, 17, 19, 10, 22, 39}
     //... so on };

Multi-dimensional arrays are also known as Rectangular Arrays, due to the fact that the size of every row will always be same. In the case of the sales array, the size is 7 and any attempt to change the size will result in an error.

Multi-dimensional Declaration and Initialization

  • Declaration: Multi-dimensional arrays are declared with comma-separated syntax to denote the multi-dimension.
1
int [,] arr;
  • Initialization: The values can be provided at the time of declaration of an array using initializer syntax.
1
2
int [,] arrIni = {
   {11, 2, 3},{14, 29, 37} };
  • Bounded initializer syntax: The size of multi-dimensional arrays can be bounded, meaning that only a defined number of one-dimensional arrays can be supplied as values. In this example, the sales array can only have two row entries.
1
2
3
int [,] arrBoundedIni = new int[2,3]{ // 2 is the number of rows and 3 is the size of each row
     {11, 2, 3},
     {14, 29, 37} };

The initializer and bounded syntax can also be combined as:

1
2
3
4
5
6
7
8
9
10
int [,] arrMixSyx = new int[2,3]{ // defined number of rows are 2
     {11, 2, 3},
     {14, 29, 37}
};

//or

int [,] arrMixSyx = new int[,]{
     {11, 2, 3},
     {14, 29, 37} };

You can use var as a place holder. The initializer and bounded syntax can be combined as:

1
2
var arrBoundedIni = new int[2,3]...
var arrMixSyx = new int[,]...

Memory Allocation

Multi-dimensional arrays are stored in a linear fashion as one long array. In memory, there will only be one single array which is logically separated into multiple dimensions of the same size (equal to the number of rows). Length and Rank properties can be used to validate the difference as:

  • Length: It will return the number of elements in an array.
1
2
3
4
int[] arr = {1,2,4};
int[,] mulArr = new int[2,3];
Console.WriteLine("Length of arr : {0}", arr.Length); // output: 3
Console.WriteLine("Length of armulArrrMul : {0}", mulArr.Length); // output: 6

The output of mulArr is 6 which is: number_of_rows * number_of_elements i.e. 2 * 3 = 6

  • Rank: It will return the number of dimensions of an array.
1
2
3
4
Console.WriteLine("Rank of arr : {0}", arr.Rank); // output: 1
Console.WriteLine("Rank of armulArrrMul : {0}", mulArr.Rank); // output: 2
Console.WriteLine("Rank of array : {0}", new string[2,3,3].Rank); // output: 3
// [2,3,3] = 2 rows(arrays) of 3 arrays, each having 3 elements

Note: C# provides a way to create multi-dimensional arrays with having different row sizes, known as a Jagged array. Unlike multi-dimensional arrays, jagged arrays are composed of several one-dimensional arrays meaning that the Rank property of jagged array will always return 1.

Array Access

The items of multi-dimensional arrays are represented as a matrix and can be simply accessed with the index value of the row and column.

1
2
3
4
5
6
7
8
9
// 0 = Section A
// 1 = Section B
string [,] sections = new string[2,3];
sections[0,0] = "Tony";
sections[0,1] = "Samy";
sections[0,2] = "Jane";
sections[1,0] = "Jack";
sections[1,1] = "Hans";
sections[1,2] = "Fred";

Loops can also be used to traverse arrays:

1
2
3
4
5
6
7
for(int row = 0; row< sections.GetLength(0); row++){
   for (int col = 0; col < sections.GetLength(1); col++)
   {
       char grade = (row == 0) ? 'A' : 'B';
       Console.WriteLine("{0} scored grade {1}",sections[row,col],grade); // demo output: Tony scored grade A
     }
}
  • GetLength: It will return the size of an array at a particular index.

foreach provides a convenient way to access all the values:

1
2
3
4
foreach (string student in sections)
{
       Console.WriteLine("{0}",student);
}

Jagged Arrays

Jagged arrays can contain references to other arrays and the sizes of other arrays can be different. The elements of jagged arrays are array references, whereas multi-dimensional arrays can only store elements and dimensions (just a logical entity). Consider an example of teams in a competition where number of team members can vary:

1
2
3
4
5
string[][] enteries = new string[3][]{
    new string[] {"TeamCS", "Dennis", "James", "Guido", "Linus"},
    new string[] {"TeamMath", "Ramanujan", "Hardy"},
    new string[] {"TeamSc", "Albert", "Tesla", "Newton"},
};

This is the example with existing data. Jagged arrays can be declared and the inner array can be initialized later:

1
2
3
4
5
6
7
string[][] enteries = new string[3][];
enteries[0] = new string[4]; // inner array initialization
enteries[1] = new string[2];
enteries[2] = new string[3];
enteries[0][0] = "TeamCS"; // data can be added later
enteries[1][1] = "Ramanujan";
enteries[2][2] = "Tesla";

Inner array references need to be initialized using the new operator before any access operation because, by default, inner arrays are initialized to null. So, any attempt to store data will result in a NullReferenceException which will crash the application.

Accessing Jagged Arrays

In jagged arrays, the inner array references can be retrieved and accessed like this:

1
2
3
4
5
string[] teamCS = enteries[0];
string[] teamMath = enteries[1];
string[] teamSc = enteries[2];

string firstMemberCS = teamCS[1];

Since a jagged array is a collection of array(s), the Length property can be used to fetch the number of elements in an array.

1
2
3
4
5
6
7
8
for (int size = 0; size < enteries.Length; size++)
{
   Console.WriteLine("Team {0}: ",enteries[size][0]); // team name
   for (int innerArrSize = 1; innerArrSize < enteries[size].Length; innerArrSize++)
   {
     Console.WriteLine(" {0}",enteries[size][innerArrSize]);// names of team members
 }
}

foreach can be used to access all the elements.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
foreach (string[] team in enteries) // string[]: for inner array
{
  foreach (string element in team)
  {
   Console.WriteLine("{0}",element);
  }
}
//or
foreach (var team in enteries)
{
 foreach (var element in team)
 {
    Console.WriteLine("{0}",element);
 }
}

Key Points

  • C# doesn't support jagged array initialization syntax to mention the size of rows and columns at the time of declaration. For 2D arrays, C# encourages the use of multi-dimensional arrays over jagged arrays because multi-dimensional arrays are more efficient, in terms of memory access and memory consumption.
1
2
3
int[][] nums = new int[3][2]; // error in c#
int[,]  nums = new int[3,2];  // valid
int[][] nums = new int[3][];  // valid

For 2d arrays, it is recommended to use multi-dimensional array or use jagged arrays with either lazy initialization or initializer syntax.

1
2
3
4
5
nums[0] = new int[1]; // lazy initialization
nums[0][0] = 12; // assigning value
int[][] nums2 = new int[2][]{ /* initializer syntax */
    new int[] { 8, 1, 99 },  new int[] { 5 }
}
  • The combination of multi-dimensional and jagged types can also be used.
1
2
3
4
5
6
7
int[][,] nums = new int[2][,]; // two multi-dimensional arrays
nums[0] = new int[1,2]; // first contains an array of 2 elements
nums[1] = new int[1,1]; // second contains an array of 1 elements

int[][,] nums = new int[2][,]{ // same as above with values
     new int[1,2]{ {1,2} },
     new int[1,1]{ {1} }, };
  • Multi-dimensional arrays are optimized for memory access and consumption because they are stored in a continuous memory location. This can be an issue when there is no large memory block available for multi-dimensional array.

I hope you found this guide illustrative and productive. Thank you for reading!

2