Google Apps Script: Как получить значения из массива?

Что такое массив и зачем он нужен

Массив в Google Apps Script, как и в JavaScript, представляет собой упорядоченную коллекцию значений. Элементы массива могут быть различных типов данных: строки, числа, булевы значения, объекты и даже другие массивы. Массивы являются фундаментальной структурой данных, используемой для хранения и обработки списков данных, таких как строки из Google Sheets, списки пользователей, результаты API-запросов и многое другое.

Использование массивов позволяет эффективно управлять группами связанных данных, упрощая их передачу, итерацию и модификацию.

Объявление и инициализация массивов

Массивы в Apps Script объявляются с использованием квадратных скобок [].

/**
 * Пример объявления и инициализации массивов.
 */
function initializeArrays(): void {
  // Пустой массив
  const emptyArray: any[] = [];

  // Массив строк (названия рекламных кампаний)
  const campaignNames: string[] = ["Поиск - Бренд", "КМС - Ремаркетинг", "Поиск - Общие ключи"];

  // Массив чисел (стоимость клика)
  const cpcValues: number[] = [15.5, 8.2, 25.0];

  // Массив с разными типами данных (не рекомендуется без веской причины)
  const mixedData: (string | number | boolean)[] = ["Кампания А", 1000, true];

  Logger.log(campaignNames);
  Logger.log(cpcValues);
}

Типы данных, хранящиеся в массивах

Apps Script позволяет хранить в массивах любые типы данных, поддерживаемые JavaScript:

  • Примитивные типы: string, number, boolean, null, undefined, symbol, bigint.
  • Объекты: включая стандартные объекты Object, Date, RegExp, а также объекты сервисов Apps Script (хотя хранение самих объектов сервисов не всегда практично, чаще хранят их идентификаторы или данные).
  • Другие массивы: создание многомерных массивов.

Основные способы получения значений из массива

Доступ к элементам массива по индексу

Наиболее прямой способ получить значение — обратиться к элементу по его индексу. Индексация массивов в Apps Script начинается с нуля.

/**
 * Демонстрация доступа к элементам массива по индексу.
 */
function accessByIndex(): void {
  const keywords: string[] = ["купить слона", "продать слона", "слон цена"];

  // Получаем первый элемент (индекс 0)
  const firstKeyword: string = keywords[0];
  Logger.log("Первое ключевое слово: %s", firstKeyword); // Вывод: Первое ключевое слово: купить слона

  // Получаем третий элемент (индекс 2)
  const thirdKeyword: string = keywords[2];
  Logger.log("Третье ключевое слово: %s", thirdKeyword); // Вывод: Третье ключевое слово: слон цена

  // Попытка доступа к несуществующему элементу вернет undefined
  const nonExistent: string | undefined = keywords[5];
  Logger.log("Несуществующий элемент: %s", nonExistent); // Вывод: Несуществующий элемент: undefined
}

Использование цикла for для итерации по массиву

Классический цикл for является надежным способом перебрать все элементы массива, когда известен его размер.

/**
 * Итерация по массиву с использованием цикла for.
 */
function iterateWithForLoop(): void {
  const ctrValues: number[] = [0.05, 0.12, 0.08, 0.15];
  const keywords: string[] = ["keyword1", "keyword2", "keyword3", "keyword4"];

  Logger.log("CTR выше 10%:");
  for (let i: number = 0; i < ctrValues.length; i++) {
    const currentCtr: number = ctrValues[i];
    const currentKeyword: string = keywords[i]; // Доступ к элементу другого массива по тому же индексу

    if (currentCtr > 0.10) {
      Logger.log("- %s: %s", currentKeyword, (currentCtr * 100).toFixed(2) + "%");
    }
  }
}

Использование цикла for...in для итерации по массиву (с предостережениями)

Цикл for...in предназначен для перебора свойств объекта, а не элементов массива. Хотя он может работать с массивами (поскольку массивы в JavaScript являются объектами), он перебирает индексы (в виде строк), а также может захватить унаследованные свойства, если они есть. Использование for...in для массивов не рекомендуется. Для итерации по значениям используйте for, for...of (если среда выполнения поддерживает) или методы массива (forEach, map).

Продвинутые методы извлечения значений

Современный JavaScript (и, соответственно, Apps Script) предоставляет мощные методы для работы с массивами.

Метод forEach(): итерация и обработка каждого элемента

Метод forEach() выполняет переданную функцию один раз для каждого элемента массива. Удобен, когда нужно выполнить действие для каждого элемента, не создавая новый массив.

/**
 * Использование forEach для обработки элементов массива.
 * @param {string[]} urls - Массив URL-адресов.
 */
function processUrls(urls: string[]): void {
  Logger.log("Обработка URL:");
  urls.forEach((url: string, index: number, arr: string[]) => {
    // url - текущий элемент
    // index - индекс текущего элемента
    // arr - сам массив, по которому идет итерация
    Logger.log("Индекс: %s, URL: %s", index, url.toUpperCase());
  });
}

// Пример вызова
// const landingPages: string[] = ["https://site.com/page1", "https://site.com/page2"];
// processUrls(landingPages);

Метод map(): создание нового массива на основе существующего

Метод map() создает новый массив с результатами вызова указанной функции для каждого элемента исходного массива. Идеально подходит для трансформации данных.

/**
 * Создание нового массива UTM-меток с помощью map.
 * @param {string[]} campaignNames - Исходные названия кампаний.
 * @param {string} source - Источник трафика.
 * @returns {string[]} Новый массив с UTM-метками.
 */
function createUtmCampaignTags(campaignNames: string[], source: string): string[] {
  const utmTags: string[] = campaignNames.map((name: string) => {
    // Преобразуем название в формат, подходящий для utm_campaign
    const formattedName: string = name.toLowerCase().replace(/\s+/g, '_');
    return `${source}_${formattedName}`;
  });
  return utmTags;
}

// Пример вызова
// const campaigns: string[] = ["Поиск - Бренд", "КМС - Ремаркетинг"];
// const utmCampaigns: string[] = createUtmCampaignTags(campaigns, "google_ads");
// Logger.log(utmCampaigns); // Вывод: ["google_ads_поиск_-_бренд", "google_ads_кмс_-_ремаркетинг"]

Метод filter(): выборка элементов по условию

Метод filter() создает новый массив со всеми элементами, прошедшими проверку (вернувшими true) в переданной функции.

/**
 * Фильтрация ключевых слов с высоким CTR.
 * @param {{keyword: string, ctr: number}[]} keywordStats - Массив объектов со статистикой.
 * @param {number} minCtr - Минимальное значение CTR для фильтрации.
 * @returns {{keyword: string, ctr: number}[]} Отфильтрованный массив.
 */
function filterHighCtrKeywords(keywordStats: {keyword: string, ctr: number}[], minCtr: number): {keyword: string, ctr: number}[] {
  const highCtrKeywords: {keyword: string, ctr: number}[] = keywordStats.filter((stat: {keyword: string, ctr: number}) => {
    return stat.ctr > minCtr;
  });
  return highCtrKeywords;
}

// Пример вызова
// const stats: {keyword: string, ctr: number}[] = [
//   { keyword: "купить слона", ctr: 0.15 },
//   { keyword: "продать слона", ctr: 0.08 },
//   { keyword: "слон цена", ctr: 0.12 }
// ];
// const filtered: {keyword: string, ctr: number}[] = filterHighCtrKeywords(stats, 0.10);
// Logger.log(filtered); // Вывод: [{keyword=купить слона, ctr=0.15}, {keyword=слон цена, ctr=0.12}]

Метод reduce(): агрегация значений массива

Метод reduce() применяет функцию-редьюсер к каждому элементу массива (слева направо), возвращая одно аккумулированное значение.

/**
 * Подсчет общей стоимости затрат на кампании.
 * @param {{name: string, cost: number}[]} campaignData - Массив данных по кампаниям.
 * @returns {number} Общая стоимость.
 */
function calculateTotalCost(campaignData: {name: string, cost: number}[]): number {
  const totalCost: number = campaignData.reduce((accumulator: number, currentCampaign: {name: string, cost: number}) => {
    // accumulator - аккумулированное значение (начинается с initialValue, если указано, иначе с первого элемента)
    // currentCampaign - текущий элемент массива
    return accumulator + currentCampaign.cost;
  }, 0); // 0 - начальное значение аккумулятора (initialValue)
  return totalCost;
}

// Пример вызова
// const costs: {name: string, cost: number}[] = [
//   { name: "Кампания 1", cost: 1500.50 },
//   { name: "Кампания 2", cost: 3200.75 },
//   { name: "Кампания 3", cost: 850.00 }
// ];
// const total: number = calculateTotalCost(costs);
// Logger.log("Общие затраты: %s", total.toFixed(2)); // Вывод: Общие затраты: 5551.25
Реклама

Работа с многомерными массивами

Многомерные массивы — это массивы, элементами которых являются другие массивы. Они часто используются в Apps Script для представления табличных данных, например, данных из Google Sheets.

Доступ к элементам многомерного массива

Доступ осуществляется последовательным указанием индексов для каждого уровня вложенности.

/**
 * Демонстрация доступа к элементам многомерного массива.
 */
function accessMultiDimensionalArray(): void {
  // Представление данных таблицы: [ [Строка1_Колонка1, Строка1_Колонка2], [Строка2_Колонка1, Строка2_Колонка2] ]
  const sheetData: (string | number)[][] = [
    ["Январь", 1500],
    ["Февраль", 1800],
    ["Март", 2100]
  ];

  // Получаем значение из первой строки (индекс 0), второй колонки (индекс 1)
  const januaryValue: string | number = sheetData[0][1];
  Logger.log("Значение за Январь: %s", januaryValue); // Вывод: Значение за Январь: 1500

  // Получаем значение из третьей строки (индекс 2), первой колонки (индекс 0)
  const marchLabel: string | number = sheetData[2][0];
  Logger.log("Метка за Март: %s", marchLabel); // Вывод: Метка за Март: Март
}

Итерация по многомерным массивам

Чаще всего используются вложенные циклы for или комбинация методов forEach, map.

/**
 * Итерация по многомерному массиву с помощью вложенных циклов for.
 * @param {(string | number)[][]} data - Многомерный массив данных.
 */
function iterateMultiDimensional(data: (string | number)[][]): void {
  Logger.log("Итерация по данным:");
  for (let i: number = 0; i < data.length; i++) { // Итерация по строкам
    const row: (string | number)[] = data[i];
    let rowString: string = "";
    for (let j: number = 0; j < row.length; j++) { // Итерация по колонкам в строке
      const cellValue: string | number = row[j];
      rowString += cellValue + "\t"; // Добавляем значение ячейки
    }
    Logger.log("Строка %s: %s", i + 1, rowString.trim());
  }
}

// Пример использования
// const reportData: (string | number)[][] = [
//   ["Campaign A", 100, 5], 
//   ["Campaign B", 250, 12],
//   ["Campaign C", 180, 9]
// ];
// iterateMultiDimensional(reportData);

Примеры использования многомерных массивов в Google Apps Script (например, работа с таблицами)

Самый частый сценарий — получение данных из диапазона Google Sheets методом getValues(), который возвращает двумерный массив Object[][] (где внутренние массивы представляют строки, а элементы в них — ячейки).

Примеры извлечения данных из массивов Google Sheets

Получение данных из диапазона в массив

Метод Range.getValues() считывает данные из указанного диапазона и возвращает их в виде двумерного массива.

/**
 * Получает данные из указанного диапазона Google Sheet.
 * @param {string} sheetName - Название листа.
 * @param {string} rangeA1Notation - Диапазон в A1-нотации (например, "A1:C10").
 * @returns {Object[][]} Двумерный массив данных.
 */
function getDataFromSheet(sheetName: string, rangeA1Notation: string): any[][] {
  const ss: GoogleAppsScript.Spreadsheet.Spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  const sheet: GoogleAppsScript.Spreadsheet.Sheet | null = ss.getSheetByName(sheetName);

  if (!sheet) {
    Logger.log("Лист '%s' не найден.", sheetName);
    return [];
  }

  const range: GoogleAppsScript.Spreadsheet.Range = sheet.getRange(rangeA1Notation);
  const values: any[][] = range.getValues();
  Logger.log("Получено %s строк данных.", values.length);
  return values;
}

// Пример вызова
// const sheetData: any[][] = getDataFromSheet("Статистика", "A2:D50");

Извлечение определенных столбцов или строк

После получения данных в виде массива, можно использовать методы map, filter или циклы для извлечения нужной информации.

/**
 * Извлекает определенный столбец из двумерного массива.
 * @param {any[][]} data - Исходный двумерный массив.
 * @param {number} columnIndex - Индекс столбца (начиная с 0).
 * @returns {any[]} Одномерный массив со значениями из указанного столбца.
 */
function extractColumn(data: any[][], columnIndex: number): any[] {
  if (!data || data.length === 0 || data[0].length <= columnIndex) {
    Logger.log("Некорректные данные или индекс столбца.");
    return [];
  }
  // Используем map для прохода по каждой строке и извлечения элемента по индексу columnIndex
  const columnData: any[] = data.map((row: any[]) => row[columnIndex]);
  return columnData;
}

/**
 * Фильтрует строки на основе значения в определенном столбце.
 * @param {any[][]} data - Исходный двумерный массив.
 * @param {number} columnIndex - Индекс столбца для проверки условия.
 * @param {any} filterValue - Значение, по которому фильтруем.
 * @returns {any[][]} Отфильтрованный двумерный массив.
 */
function filterRowsByColumnValue(data: any[][], columnIndex: number, filterValue: any): any[][] {
   if (!data || data.length === 0 || data[0].length <= columnIndex) {
    Logger.log("Некорректные данные или индекс столбца.");
    return [];
  }
  const filteredData: any[][] = data.filter((row: any[]) => {
    return row[columnIndex] === filterValue;
  });
  return filteredData;
}

// Пример вызова
// const allData: any[][] = getDataFromSheet("Лист1", "A1:E100");
// // Получаем массив только из второго столбца (индекс 1)
// const campaignNames: any[] = extractColumn(allData, 1);
// Logger.log("Названия кампаний: %s", campaignNames);
//
// // Получаем строки, где значение в третьем столбце (индекс 2) больше 1000
// const highCostRows: any[][] = allData.filter((row: any[]) => row[2] > 1000);
// Logger.log("Строки с затратами > 1000: %s строк", highCostRows.length);
//
// // Получаем строки, где значение в первом столбце (индекс 0) равно "Активна"
// const activeCampaigns: any[][] = filterRowsByColumnValue(allData, 0, "Активна");
// Logger.log("Активные кампании: %s строк", activeCampaigns.length);

Обработка данных, полученных из Google Sheets

Объединяя методы получения данных и методы работы с массивами (map, filter, reduce, forEach), можно эффективно обрабатывать табличные данные.

/**
 * Пример: Рассчитывает суммарные клики для активных кампаний из данных Google Sheet.
 */
function calculateClicksForActiveCampaigns(): void {
  const sheetName: string = "Campaign Performance"; // Название листа
  const dataRange: string = "A2:D"; // Диапазон с данными (Статус, Кампания, Клики, Затраты)

  const allData: any[][] = getDataFromSheet(sheetName, dataRange);

  if (allData.length === 0) {
    Logger.log("Нет данных для обработки.");
    return;
  }

  // Индексы столбцов (начиная с 0)
  const STATUS_COL: number = 0;
  const CLICKS_COL: number = 2;

  // 1. Фильтруем только активные кампании (предполагаем, что статус "Active" в первом столбце)
  const activeCampaignsData: any[][] = allData.filter((row: any[]) => row[STATUS_COL] === "Active");

  // 2. Используем reduce для суммирования кликов (третий столбец, индекс 2)
  const totalClicks: number = activeCampaignsData.reduce((sum: number, row: any[]) => {
    const clicks: number = typeof row[CLICKS_COL] === 'number' ? row[CLICKS_COL] : 0;
    return sum + clicks;
  }, 0);

  Logger.log("Суммарные клики по активным кампаниям: %s", totalClicks);
}

// Пример вызова
// calculateClicksForActiveCampaigns();

Освоение различных методов извлечения и обработки данных из массивов является ключевым навыком для эффективной работы с Google Apps Script, особенно при автоматизации задач, связанных с Google Sheets, Google Ads и другими сервисами Google.


Добавить комментарий