Как задать диапазон в с
В C# 8.0 была добавлена новая функциональность — индексы и диапазоны, которые упрощают получение из массивов подмассивов. Для этого в C# есть два типа: System.Range и System.Index . Оба типа являются структурами. Тип Range представляет некоторый диапазон значений в некоторой последовательность, а тип Index — индекс в последовательности.
Индексы
Индекс фактически представляет числовое значение, и при определении индекса мы можем указать это значение:
В данном случае индекс представляет третий элемент последовательности (индексация начинается с 0).
С помощью специального оператора ^ можно задать индекс относительно конца последовательности.
Теперь индекс представляет второй элемент с конца последовательности, то есть предпоследний элемент.
Используем индексы для получения элементов массива:
Фактически для данной задачи индексы не нужны, и мы можем воспользоваться стандартными возможностями массивов:
То есть в подобных ситуациях плюсом индексов является большая удобочитаемость. Так, people[^2] более читабельно, чем people[people.Length — 2] .
Диапазон
Диапазон представляет часть последовательности, которая ограничена двумя индексами. Начальный индекс включается в диапазон, а конечный индекс НЕ входит в диапазон. Для определения диапазона применяется оператор .. :
В данном случае диапазон myRange1 включает элементы с 1 индекса по 4-й индекс (не включая). При этом элемент по 4-му индексу не включается в диапазон. При этом границы диапазона задаются не просто числами, а именно объектами Index. То есть следующие определения диапазонов будут равноценны:
Практическое применение диапазонов — получим со второго по четвертый элементы массива:
Результатом операции people[1..4] является подмассив элементов с 1 по 3 индексы (включая). Консольный вывод:
Мы можем задать для диапазона только конечный индекс. В этом случае начальным индексом по умолчанию будет 0.
Либо, наоборот, задать только начальный индекс, тогда конечным индексом будет последний индекс последовательности:
Используя индексы относительно конца последовательности, можно получать диапазон относительно конца последовательности:
Кроме массивов индексы и диапазоны также применяются к объектам Span и ReadOnlySpan:
Диапазоны (Ranges) в C# 8
Пусть в нашей программе есть массив целых чисел numbers :
Перед нами стоит задача: получить новый массив, вырезав из массива numbers элементы от индекса 2 до индекса 4 включительно, то есть должен получится массив [4, 2, 3] .
Решение 1
Самое первое и простое решение, которое приходит в голову — это решение в лоб:
Создадим результирующий массив целых чисел result размером 3 :
Пройдемся циклом по нужным индексам массива numbers , а именно с 2 до 4 включительно:
Запишем в результирующий массив result нужные значения:
Выведем массив result и убедимся, что все ОК:
С задачей мы справились. Но есть некоторые недостатки:
Для решения такой маленькой задачи, пришлось пройтись циклом.
По коду не сразу понятно, что он делает. Таким образом страдает читаемость.
Также можно ошибиться с индексами (относится к начинающим программистам).
Следовательно, такое решение нас не устраивает.
Решение 2
Немногие знают, что у списка ( List ) есть готовый метод GetRange(int index, int count) , который получает из списка нужный диапазон элементов. Метод первым параметром принимает index — индекс начала диапазона, а вторым параметром count — количество элементов, которые нужно получить. Например:
GetRange(0, 5) — получает 5 элементов, начиная с индекса 0.
GetRange(3, 10) — получает 10 элементов, начиная с индекса 3.
Тогда сделаем следующее:
Для того чтобы мы воспользовались готовым методом GetRange , преобразуем массив в список с помощью метода ToList :
Воспользуемся методом GetRange . Нам нужно взять 3 элемента, начиная с индекса 2 :
Метод GetRange вернул результат в виде списка ( List<int> ). Для того чтобы преобразовать его в массив, воспользуемся методом ToArray :
Выведем массив result и убедимся, что все ОК:
С задачей мы справились. Но есть некоторые недостатки:
Для решения такой маленькой задачи, пришлось воспользоваться тремя дополнительными методами.
По коду не сразу понятно, что он делает. Таким образом страдает читаемость.
Также можно ошибиться при передаче параметров в метод GetRange (относится к начинающим программистам).
Данные преобразования ресурсоемкие по памяти и производительности. Вызовы ToList , ToArray проходятся по коллекции и выделяют новую память.
Следовательно, такое решение нас не устраивает.
Решение 3
Можно еще воспользоваться технологией LINQ , а именно двумя методами:
Skip(int count) — возвращает все элементы коллекции, кроме первых count .
Take(int count) — возвращает первые count элементов коллекции.
В нашем случае, для того, чтобы взять элементы массива от индекса 2 до индекса 4 включительно, нужно пропустить 2 элемента последовательности, а затем взять первые 3 элемента. Как раз получатся элементы с индексами от 2 до 4 .
Посмотрим в коде:
С задачей мы справились. Но есть некоторые недостатки:
Для решения такой маленькой задачи, пришлось воспользоваться тремя дополнительными методами.
Можно ошибиться при передаче параметров в методы Skip и Take (относится к начинающим программистам).
Данные преобразования ресурсоемкие по памяти и производительности.
Следовательно, такое решение нас не устраивает.
Решение 4
Есть еще статический метод Copy у класса Array :
Данный метод копирует элементы из одного массива в другой. Давайте поясним каждый параметр:
Array sourceArray — массив, с которого копируем элементы.
int sourceIndex — с какого индекса из массива sourceArray начинаем копировать элементы.
Array destinationArray — массив, в который копируются элементы.
int destinationIndex — начиная с какого индекса в результирующем массиве destinationArray вставляются элементы.
int length — количество элементов, которое нужно скопировать.
Давайте воспользуемся данным методом:
Создадим результирующий массив целых чисел result размером 3 :
Вызываем метод Copy . Передаем массив numbers и индекс 2 — откуда начинаем вырезать элементы. Затем передаем результирующий массив result и индекс 0 — с какого индекса вставляются элементы. А затем передаем 3 — количество элементов, которое нужно скопировать:
Выведем массив result и убедимся, что все ОК:
С задачей мы справились. Но есть некоторые недостатки:
Легко можно ошибиться при передаче параметров в метод Copy (относится к начинающим программистам).
Не сразу понятно как использовать метод Copy , ведь он ничего не возвращает. Нужно понять, что результат возвращается в массиве, который был передан третьим параметром.
Следовательно, такое решение нас не устраивает.
Решение 5
В C# 8 версии добавили дополнительную функциональность для работы с диапазонами ( Range ). Теперь для решения нашей задачи можно написать вот так:
То есть, для того чтобы получить некоторый диапазон из коллекции, нужно в квадратных скобках указать начальный индекс, затем .. и наконец индекс конца (. НЕ включительно . ).
numbers[3..10] — вырезает элементы, начиная с индекса 3 и заканчивая индексом 9 . Напоминаю, что правая граница не включается.
numbers[1..7] — вырезает элементы, начиная с индекса 1 и заканчивая индексом 6 .
Если индексы будут равны между собой, то в результате получится массив нулевой длины:
Если первый индекс будет больше второго индекса, то возникнет исключение ArgumentOutOfRangeException во время выполнения программы:
Можно использовать также индексацию справа налево ( Indices ), введенную тоже в C# 8 версии, про которую говорили совсем недавно:
Можно делать еще более веселые штучки:
Например, для получения первых n элементов с помощью диапазонов, нужно написать numbers[0..n] . Так вот, специально для случаев, когда вы хотите взять диапазон с начала массива (когда первый индекс равен 0 ), придумали упрощение: можно индекс равный 0 опускать, то есть написать вот так: numbers[..n] . Такая запись более предпочтительна.
Например, для получения всех элементов, кроме первых n с помощью диапазонов, нужно написать numbers[n..numbers.Length] . Специально для случаев, когда вы хотите взять все элементы, кроме первых n (начиная с индекса n и до конца массива), придумали упрощение. Так как второй индекс всегда равен длине массива, то его можно опустить, то есть написать вот так: numbers[n..] . Такая запись более предпочтительна.
Ну и комбинация этих двух подходов. Для получения полной копии массива, можно написать вот так: numbers[..] , то есть опустить оба индекса. Это означает взять диапазон от начала массива до конца.
Что там под капотом?
На самом деле любой диапазон в C# 8 версии можно хранить в новом типе данных Range . Он находится в пространстве имен ( namespace ) System , следовательно, никакой дополнительный using при его использовании не нужно писать.
У Range существует два конструктора:
Range() – создает пустой диапазон.
Range(Index start, Index end) – создает диапазон от индекса start (включительно) и до индекса end (НЕ включительно).
Рассмотрим на примерах:
Заметьте, что объект типа Range передается в качестве индекса в квадратные скобки ( [] ).
Проведем соответствие между двумя разными записями:
Укороченная версия
Версия с Range
numbers[new Range(2, 5)]
numbers[new Range(^6, ^2)]
В Range реализовано неявное преобразование укороченной записи (например 2..5 ) к Range . Вот как это работает:
У Range переопределен метод Equals :
А можно вообще вот так:
Здесь сначала происходит неявное преобразование укороченной записи к Range , а потом вызов Equals .
У Range переопределен также метод ToString :
Заметьте, что для индексации с конца выводится ^ перед индексом.
Также теперь мы можем в методы передавать диапазон:
Выводы:
Структура Range позволяет создать экземпляр, к которому можно обращаться многократно.
Создать диапазон чисел в C++
мне нужна помощь в определении диапазона чисел. У меня ошибка в коде и результат выглядит так:
Input: rangeStart = 1, rangeEnd = 23, periodLength = 10
Output: 1 2 3 4 5 6 7 8 9 10 11-20 21 22 23
Мне нужно, чтобы это было:
Input: rangeStart = 1, rangeEnd = 23, periodLength = 10
Output: 1-10 11-20 21 22 23
Буду признателен за любой ответ
Лишние вызовы функций, создание объектов и арифметические действия, тормозят программу.Часто лучше просто генерировать числа с заданным шагом и стартовым значением, пока не достигли конца. Представлю вариант:
Чисто исходя из ваших примеров ввода вывода:
В вашем коде вы на первой итерации получаете 1 и выписываете весь период, а после периода вы прибавляете слишком много и снова выписываете полный период. Это более заметно если rangeEnd взять большой.
И, возможно, вам будет лучше использовать enum для periodType .
Дизайн сайта / логотип © 2023 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2023.6.15.43497
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
Определить диапазон чисел в C / C ++
Пользователь вводит 1 3, 4 7, 7 10 и мы определяем диапазон 1-3 как часть одного диапазона, 4-7 как другой и так далее. и если вводится число 8, например, мы получаем выход как диапазон 3.
Рассматривал создание массива int arr [10] и как пользовательские входы 1 3, например, тогда arr [0] = 1 и arr [2] = 1, затем для 4 7 как arr [ 3] = 2 и arr [6] = 2. Но это пропускает числа между ними, и если мы зацикливаем от 0 до 2 и от 3 до 6. В большем масштабе с массивом дольше 10 это будет неэффективно.