Перебор массивов. Цикл foreach
Цикл foreach предназначен для перебора элементов в контейнерах, в том числе в массивах. Формальное объявление цикла foreach:
foreach (тип_данных название_переменной in контейнер)
Например:
int[] numbers = new int[] { 1, 2, 3, 4, 5 };
foreach (int i in numbers)
{
Console.WriteLine(i);
}
Здесь в качестве контейнера выступает массив данных типа int. Поэтому мы объявляем переменную с типом int
Подобные действия мы можем сделать и с помощью цикл for:
int[] numbers = new int[] { 1, 2, 3, 4, 5 };
for (int i = 0; i < numbers.Length; i++)
{
Console.WriteLine(numbers[i]);
}
В то же время цикл for более гибкий по сравнению с foreach. Если foreach последовательно извлекает элементы контейнера и только для чтения, то в цикле for мы можем перескакивать на несколько элементов вперед в зависимости от приращения счетчика, а также можем изменять элементы:
int[] numbers = new int[] { 1, 2, 3, 4, 5 };
for (int i = 0; i < numbers.Length; i++)
{
numbers[i] = numbers[i] * 2;
Console.WriteLine(numbers[i]);
}
Многомерные массивы
Массивы бывают многомерными. В предыдущих примерах мы создавали одномерные массивы, а теперь создадим двухмерный:
int[] nums1 = new int[] { 0, 1, 2, 3, 4, 5 };
int[,] nums2 = { { 0, 1, 2 }, { 3, 4, 5 } };
Визуально оба массива можно представить следующим образом:
Одномерный массив nums1
Двухмерный массив nums2
Поскольку массив nums2 двухмерный, он представляет собой простую таблицу. Объявление трехмерного массива могло бы выглядеть так:
int[,,] nums3 = new int[2, 3, 4];
Все возможные способы определения двухмерных массивов:
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 } };
Определенную сложность может представлять перебор многомерного массива. Прежде всего надо учитывать, что длина такого массива - это совокупное количество элементов.
int[,] mas = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 }, { 10, 11, 12 } };
foreach (int i in mas)
Console.Write($"{i} ");
Console.WriteLine();
В данном случае длина массива mas равна 12. И цикл foreach выводить все элементы массива в строку:
Но что если мы хотим отдельно пробежаться по каждой строке в таблице? В этом случае надо получить количество элементов в размерности. В частности, у каждого массива есть метод GetUpperBound(dimension), который возвращает индекс последнего элемента в определенной размерности. И если мы говорим непосредственно о двухмерном массиве, то первая размерность (с индексом 0) по сути это и есть таблица. И с помощью выражения mas.GetUpperBound(0) + 1 можно получить количество строк таблицы, представленной двухмерным массивом. А через mas.Length / rows можно получить количество элементов в каждой строке:
int[,] mas = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 }, { 10, 11, 12 } };
int rows = mas.GetUpperBound(0) + 1;
int columns = mas.Length / rows;
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < columns; j++)
{
Console.Write($"{mas[i, j]} \t");
}
Console.WriteLine();
}
Структуры
Кроме базовых элементарных типов данных и перечислений в C# имеется и составной тип данных, который называется структурой. Структуры могут содержать в себе обычные переменные и методы.
Для примера [5] создадим структуру Book, в которой будут храниться переменные для названия, автора и года издания книги. Кроме того, структура будет содержать метод для вывода информации о книге на консоль:
struct Book
{
public string name;
public string author;
public int year;
public void Info()
{
Console.WriteLine($"Книга '{name}' (автор {author}) была издана в {year} году");
}
}
Чтобы можно было использовать переменные и методы структуры из любого места программы мы ставим перед переменными и методом модификатор доступа public
Используем структуру на практике:
using System;
namespace Structures
{
class Program
{
static void Main(string[] args)
{
Book book;
book.name = "Война и мир";
book.author = "Л. Н. Толстой";
book.year = 1869;
//Выведем информацию о книге book на экран
book.Info();
Console.ReadLine();
}
}
struct Book
{
public string name;
public string author;
public int year;
public void Info()
{
Console.WriteLine($"Книга '{name}' (автор {author}) была издана в {year} году");
}
}
}
Структуру можно задать как внутри пространства имен (как в данном случае), так и внутри класса, но не внутри метода.
По сути структура Book представляет новый тип данных. Мы также можем использовать массив структур:
Book[] books=new Book[3];
books[0].name = "Война и мир";
books[0].author = "Л. Н. Толстой";
books[0].year = 1869;
books[1].name = "Преступление и наказание";
books[1].author = "Ф. М. Достоевский";
books[1].year = 1866;
books[2].name = "Отцы и дети";
books[2].author = "И. С. Тургенев";
books[2].year = 1862;
foreach (Book b in books)
{
b.Info();
}
Работа со строками