Skip to main content

Arrays

An array represents a set of data of the same type. Declaring an array is similar to declaring a variable, except that square brackets are placed after the type:

type_variable[] array_name;

For example, let's define an array of integers:

int[] numbers;

After defining an array variable, we can assign a specific value to it:

int[] nums = new int[4];

Here first we have declared an array nums which will store data of int type. Then using the new operation we allocated memory for 4 array elements: new int[4]. The number 4 is also called the array length. With this definition, all the elements get the default value, which is provided for their type. For the int type, the default value is 0.

We can also immediately specify values for these elements:

int[] nums2 = new int[4] { 1, 2, 3, 5 };

int[] nums3 = new int[] { 1, 2, 3, 5 };

int[] nums4 = new[] { 1, 2, 3, 5 };

int[] nums5 = { 1, 2, 3, 5 };

All of the above methods will be equivalent.

Arrays of other types can be defined in a similar way, for example, an array of values of type string:

string[] people = { “Tom”, “Sam”, “Bob” };

Starting with C# 12, you can use collection expressions, which involve enclosing array elements in square brackets, to define arrays:

int[] nums1 = [ 1, 2, 3, 5 ];
int[] nums2 = []; // empty array

Indexes and retrieval of array elements

Indexes are used to refer to array elements. An index represents the number of an element in the array, with the numbering starting at zero, so the index of the first element will be 0, the index of the fourth element will be 3.

By using indices, we can get the elements of the array:

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

// get an element of the array
Console.WriteLine(numbers[3]); // 5

// getting an array element into a variable
var n = numbers[1]; // 2
Console.WriteLine(n); // 2

We can also change the array element by index:

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

// change the second element of the array
numbers[1] = 505;

Console.WriteLine(numbers[1]); // 505

And since we have the array defined for only 4 elements, we can't address, for example, the sixth element. If we try to do so, we will get a runtime error:

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

Console.WriteLine(numbers[6]); // ! Error - there are only 4 items in the array

Length property and array length

each array has a Length property, which stores the length of the array. For example, let's get the length of the numbers array created above:

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

Console.WriteLine(numbers.Length); // 4

To get the length of the array, the Length property is specified after the array name with a dot: numbers.Length.

Getting elements from the end of the array

Due to the presence of the Length property, we can calculate the index of the last element of the array - this is the length of the array - 1. For example, if the length of the array is 4 (that is, the array has 4 elements), then the index of the last element will be 3. And, using the Length property, we can easily get the elements from the end of the array:

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

Console.WriteLine(numbers[numbers.Length - 1]); // 5 - first from the end or last element
Console.WriteLine(numbers[numbers.Length - 2]); // 3 - second from the end or penultimate element
Console.WriteLine(numbers[numbers.Length - 3]); // 2 - the third element from the end.

However, with this approach, expressions of the numbers.Length - 1 type, the sense of which is to get a certain element from the end of the array, make the code heavier. So, since C# 8.0, a special operator ^ has been added to the language, which can be used to specify an index relative to the end of the collection.

Let's rewrite the previous example using the ^ operator:

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

Console.WriteLine(numbers[^1]); // 5 is the first from the end or the last element
Console.WriteLine(numbers[^2]); // 3 - second from the end or penultimate element
Console.WriteLine(numbers[^3]); // 2 - third element from the end

Array enumeration

We can use different types of loops to loop through arrays. For example, the foreach loop:

int[] numbers = { 1, 2, 3, 4, 5 };
foreach (int i in numbers)
{
Console.WriteLine(i);
}

Here we have an array of data of type int as the container. Therefore, we declare a variable with the int type

We can do similar actions using the for loop:

int[] numbers = { 1, 2, 3, 4, 5 };
for (int i = 0; i < numbers.Length; i++)
{
Console.WriteLine(numbers[i]);
}

At the same time, the for loop is more flexible compared to foreach. Whereas foreach retrieves container elements sequentially and is read-only, in the for loop we can jump forward a few elements depending on the increment of the counter, and we can also modify elements:

int[] numbers = { 1, 2, 3, 4, 5 };
for (int i = 0; i < numbers.Length; i++)
{
numbers[i] = numbers[i] * 2;
Console.WriteLine(numbers[i]);
}

You can also use other kinds of loops, such as while:

int[] numbers = { 1, 2, 3, 4, 5 };
int i = 0;
while(i < numbers.Length)
{
Console.WriteLine(numbers[i]);
i++;
}

Multidimensional arrays

Arrays are characterized by such a concept as rank or number of dimensions. Above we considered arrays that have one dimension (i.e. their rank is 1) - such arrays can be represented as a row (row or column) element. But arrays can also be multidimensional. Such arrays have a number of dimensions (i.e. their rank) greater than 1.

Arrays that have two dimensions (rank is 2) are called two-dimensional. For example, let's create one-dimensional and two-dimensional arrays that have the same elements:

int[] nums1 = new int[] { 0, 1, 2, 3, 4, 5 };

int[,] nums2 = { { { 0, 1, 2 }, { 3, 4, 5 } } };

Visually, both arrays can be represented as follows:

One-dimensional array nums1

| 0 | 1 | 2 | 3 | 4 | 5 |

Two-dimensional array nums2

| 0 | 1 | 2 |
| 3 | 4 | 5 |

Because the nums2 array is two-dimensional, it is a simple table. All possible ways to define two-dimensional arrays:

int[,] nums1;
int[,] nums2 = new int[2, 3];
int[,] nums3 = new int[2, 3] { { { 0, 1, 2 }, { 3, 4, 5 } } };
int[,] nums4 = new int[,] { { 0, 1, 2 }, { 3, 4, 5 } } };
int[,] nums5 = new [,]{ { 0, 1, 2 }, { 3, 4, 5 } } };
int[,] nums6 = { { { 0, 1, 2 }, { 3, 4, 5 } } };

Arrays can have more dimensions as well. The declaration of a three-dimensional array might look like this:

int[,,,] nums3 = new int[2, 3, 4];

Accordingly, there can be four-dimensional arrays and arrays with a large number of dimensions. But in practice one-dimensional and two-dimensional arrays are usually used.

A certain difficulty can be presented by the enumeration of a multidimensional array. First of all, we should take into account that the length of such an array is the cumulative number of elements.

int[,] numbers = { { { 1, 2, 3 }, { 4, 5, 6 } } };
foreach (int i in numbers)
Console.Write($"\{i\});

In this case, the length of the numbers array is 6. And the foreach loop outputs all the elements of the array into a string:

1 2 3 4 5 6

But what if we want to separately run each row in the table? In this case, we need to get the number of elements in the dimension. In particular, each array has a GetUpperBound(dimension_number) method, which returns the index of the last element in a certain dimension. And if we are talking directly about a two-dimensional array, the first dimension (with index 0) is essentially a table. And with the help of the expression

numbers.GetUpperBound(0) + 1

you can get the number of rows of the table represented by the two-dimensional array. And through

numbers.Length / number_rows

you can get the number of elements in each row:

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

int rows = numbers.GetUpperBound(0) + 1; // number of rows
int columns = numbers.Length / rows; // number of columns
// or like this
// int columns = numbers.GetUpperBound(1) + 1;

for (int i = 0; i < rows; i++)
{
for (int j = 0; j < columns; j++)
{
Console.Write($“{{numbers[i, j]} \t)
}
Console.WriteLine();
}
1 2 3
4 5 6

Array of arrays

We must distinguish from multidimensional arrays the array of arrays or the so-called “cog array”:

int[][] nums = new int[3][];
nums[0] = new int[2] { 1, 2 }; // allocate memory for the first subarray
nums[1] = new int[3] { 1, 2, 3 }; // allocate memory for the second subarray
nums[2] = new int[5] { 1, 2, 3, 4, 5 }; // allocate memory for the third subarray

Here two groups of square brackets indicate that this is an array of arrays, i.e. an array that in its turn contains other arrays. And the length of the array is specified only in the first square brackets, all the subsequent square brackets must be empty: new int[3][]. In this case, the nums array contains three arrays. And the dimensionality of each of these arrays may not coincide.

Alternative definition of an array of arrays:

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

Notched array nums

| 1 | 2 |
| 1 | 2 | 3 |
| 1 | 2 | 3 | 4 | 5 |

Using nested loops, you can loop through cogged arrays. For example:

int[][] numbers = new int[3][];
numbers[0] = new int[] { 1, 2 };
numbers[1] = new int[] { 1, 2, 3 };
numbers[2] = new int[] { 1, 2, 3, 4, 5 };
foreach(int[] row in numbers)
{
foreach(int number in row)
{
Console.Write($“{number} \t”)
}
Console.WriteLine();
}

// loop for
for (int i = 0; i<numbers.Length;i++)
{
for (int j =0; j<numbers[i].Length; j++)
{
Console.Write($“{”{numbers[i][j]} \t)
}
Console.WriteLine();
}

Basic concepts of arrays

Summarize the basic concepts of arrays:

  • Rank: the number of dimensions of an array

  • Dimension length: the length of a single dimension of an array

  • Array length (array length): the number of all elements of an array

For example, let's take an array

int[,] numbers = new int[3, 4];

The numbers array is two-dimensional, that is, it has two dimensions, so its rank is 2. The length of the first dimension is 3 and the length of the second dimension is 4. The length of the array (i.e. the total number of elements) is 12.