Обобщенные срезы в массивах значений

До этого момента мы пользовались срезами, которые выделяли подмножество значений из одномерного массива. Но как быть с двумерными или трехмерными массивами? Для этого придуманы обобщенные срезы, да, именно эти срезы выделяют подмножество из n-мерных массивов. Как и обычные срезы, обобщенные срезы принимают три параметра, которые определяют параметры среза. Однако, в обобщенных срезах второй и третий параметры задаются массивом. То есть размер подмножества и шаг задаются как массивы, смотрим пример:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20-исходный массив
Параметры обобщенного среза:

  • начальный индекс: 0;
  • количество элементов: {3, 2}
  • размер шага: {7, 5}

Полученный результат:

  • 0 5
  • 7 13
  • 14 19

Итак, каким же образом у нас получился такой результат? Во-первых, исходный массив всегда является одномерным массивом, полученный массив также является одномерным, хотя я его представил как двумерный. Это было сделано для более удобного восприятия результата среза. По сути результат был бы таким — 0 5 7 13 14 19, но такой вид массива труден к восприятию.

Вернемся к параметрам среза. С первым параметром среза все ясно, так же как и в простых срезах, первый параметр указывает на первый элемент выборки. Второй параметр среза — это количество элементов, которые попадут в подмножество, оно задается массивом. В нашем примере указаны числа 3 и 2, значит подмножество будет состоять из трех серий в каждой серии два элемента. В итоге, если перемножить эти два числа получится 6 элементов. Собственно в полученном результате мы видим три строки, два столбца и элементов всего — 6.
Перейдем к третьему параметру среза — это шаг выборки, и он также задается массивом. В массиве указаны два числа: 7 и 5. Что это значит? Число 7 — это шаг между сериями подмножества. Число пять — это шаг между элементами в одной серии. По результату это хорошо видно.

Вот еще один пример среза:

  • индекс: 2;
  • размер подмножества: {2, 6}
  • шаг: {4, 10}

Полученное подмножество:

  • 2 12 22 32 42 52
  • 6 16 26 36 46 56

Как видите, тут мы получили 2 серии по 6 элементов, серии разделены расстоянием в 4 элемента. В одной серии между элементами расстояние 10. В этом примере я также из полученного подмножества собрал двухмерный массив. На самом же деле получится такой набор элементов: 2 6 12 16 22 26 32 36 42 46 52 56. Как видите, в этом примере числа из двух серий смешаны, это связано с тем, что шаг между сериями меньше шага между элементами одной серии. Давайте рассмотрим пример программы, в которой используются обобщенные срезы:

#include <iostream>
#include <valarray>     // заголовочный файл массивов значений
#include <iomanip>

using namespace std;
int main()
{
    valarray<int> array(0, 60);

    // определяем массивы обобщенного среза
    size_t length[] = {2, 6};   // две серии, в каждой серии по 6 элементов
    size_t stride[] = {4, 10};  // шаг между сериями - 4 элемента, шаг между элементами одной серии - 10.

    // создаем два объекта, в которые помещаем массивы срезов
    valarray<size_t> len(length, 2);
    valarray<size_t> str(stride, 2);

    array[gslice(2, len, str)] = 1; // по срезу присваиваем всем элементам подмножества единицу

    cout << "Измененный массив значений: ";
    for(int i = 0; i < array.size(); i++) {
        cout << array[i] << " ";
    }

    cout << "\nПодмножество(индексы элементов массива): ";
    for(int i = 0, j = 0; i < array.size(); i++, j++) {
            if ( array[i] == 1) {
                cout << setw(2) << i << " ";
            }
    }
    return 0;
}

Результат:

CppStudio.com
Измененный массив значений: 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 
Подмножество(индексы элементов массива):  2  6 12 16 22 26 32 36 42 46 52 56

Просто, чтобы уточнить, в этой программе задан срез из предыдущего примера. В строках 11-12 определены массивы, которые далее в программе будут использоваться для указания второго и третьего параметров среза. Кроме того, типы данных этих массивов должны быть size_t. Так как во второй и третий параметры среза передаются массивы, последние должны иметь тип данных valarray, поэтому переводим массивы из строк 11-12 в valarray, строки 15-16. Теперь когда массивы полностью готовы, мы их передаем в функцию обобщенного среза gslice, строка 18.

Обратите внимание, что у функции обобщенного среза немного другое имя. Еще, в строке 18 каждому элементу подмножества присваиваем 1. Ну и в конце программы, в строках 26 — 30 мы выводим индексы элементов подмножества, это тоже видно в результате.
Еще хочу обратить ваше внимание на то, что срезы можно задавать n-мерные. Мы создавали пока только двухмерные подмножества. Если хотите трехмерное подмножество просто добавте в массивы срезов еще по одному значению, например, так:

size_t length[] = {2, 6, 4};   
size_t stride[] = {4, 10, 3};

Тогда у вас получится срез с тремя измерениями, но запомните, что количество элементов в массивах среза должно быть одинаковым, иначе получите подобную ошибку:

The program has unexpectedly finished.

Это была не простая темя для изучения, советую вам поэкспериментировать немного с моей программой, для более лучшего понимания этой темы. Далее мы приступим к изучению масок для срезов.

Автор: Marienko L.
Дата: 25.01.2014
Поделиться:

Комментарии

  1. TonyVCLCSA .

    valarray<size_t> len(length, 2);

    Здесь 2 это sizeof(length) / sizeof(length[0]).

    Это объяснялось в теме по массивам значений.

    Но у меня с ним не работает, зато если инициализирую без 2, то все работает. Может это особенность sololearn на а андроид, а может чтото поменялось. Судя по комментариям, статье 2 года минимум.

     

  2. luda

    В первом примере, в «Полученный результат:» вместо «7 13″ должно быть 7 12.

  3. blablabla

    ничего непонятно.

    как массив записан в другой массив, и что значит в строках 15-16 цифра 2?

Оставить комментарий

Вы должны войти, чтобы оставить комментарий.