Концепции функционального программирования

Введение в функциональное программирование

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

Основная концепция, отличающая функциональное программирование от процедурного, — отсутствие побочных эффектов . Это означает, что функции, которые вы пишете, не используют данные, находящиеся вне функции, и не обновляют их. Как вы увидите в примерах ниже, можно реструктурировать задачу так, чтобы её можно было решить с помощью функций без побочных эффектов, которые гораздо лучше подходят для параллельного выполнения.

Для циклов

Использование циклов for в Earth Engine не рекомендуется. Такого же результата можно добиться с помощью операции map() , где указывается функция, которая может быть применена к каждому элементу независимо. Это позволяет системе распределять обработку между разными машинами.

В примере ниже показано, как можно взять список чисел и создать другой список с квадратами каждого числа с помощью map() :

Редактор кода (JavaScript)

// This generates a list of numbers from 1 to 10.
var myList = ee.List.sequence(1, 10);

// The map() operation takes a function that works on each element independently
// and returns a value. You define a function that can be applied to the input.
var computeSquares = function(number) {
  // We define the operation using the EE API.
  return ee.Number(number).pow(2);
};

// Apply your function to each item in the list by using the map() function.
var squares = myList.map(computeSquares);
print(squares);  // [1, 4, 9, 16, 25, 36, 49, 64, 81]

Условия «если/иначе»

Другая распространённая проблема, с которой сталкиваются новые пользователи, привыкшие к процедурной парадигме программирования, — это правильное использование условных операторов if/else в Earth Engine. Хотя API предоставляет алгоритм ee.Algorithms.If() , его использование настоятельно не рекомендуется в пользу более функционального подхода с использованием map() и фильтров. Earth Engine использует отложенное выполнение , то есть вычисление выражения откладывается до тех пор, пока его реализованное значение не потребуется. В некоторых случаях эта модель выполнения будет оценивать как истинные, так и ложные альтернативы оператора ee.Algorithms.If() . Это может привести к дополнительным вычислениям и использованию памяти в зависимости от выражений и ресурсов, необходимых для их выполнения.

Допустим, вы хотите решить вариант приведенного выше примера, где требуется вычислить квадраты только нечетных чисел. Функциональный подход к решению этой задачи без условий if/else показан ниже:

Редактор кода (JavaScript)

// The following function determines if a number is even or odd.  The mod(2)
// function returns 0 if the number is even and 1 if it is odd (the remainder
// after dividing by 2).  The input is multiplied by this remainder so even
// numbers get set to 0 and odd numbers are left unchanged.
var getOddNumbers = function(number) {
  number = ee.Number(number);   // Cast the input to a Number so we can use mod.
  var remainder = number.mod(2);
  return number.multiply(remainder);
};

var newList = myList.map(getOddNumbers);

// Remove the 0 values.
var oddNumbers = newList.removeAll([0]);

var squares = oddNumbers.map(computeSquares);
print(squares);  // [1, 9, 25, 49, 81]

Эта парадигма особенно применима при работе с коллекциями. Если вы хотите применить к коллекции другой алгоритм в зависимости от определённых условий, предпочтительный способ — сначала отфильтровать коллекцию по условию, а затем применить функцию map() к каждому подмножеству. Это позволяет системе распараллелить операцию. Например:

Редактор кода (JavaScript)

// Import Landsat 8 TOA collection and filter to 2018 images.
var collection = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA')
  .filterDate('2018-01-01', '2019-01-01');

// Divide the collection into 2 subsets and apply a different algorithm on them.
var subset1 = collection.filter(ee.Filter.lt('SUN_ELEVATION', 40));
var subset2 = collection.filter(ee.Filter.gte('SUN_ELEVATION', 40));

// Multiply all images in subset1 collection by 2;
// do nothing to subset2 collection.
var processed1 = subset1.map(function(image) {
  return image.multiply(2);
});
var processed2 = subset2;

// Merge the collections to get a single collection.
var final = processed1.merge(processed2);
print('Original collection size', collection.size());
print('Processed collection size', final.size());

Накопительная итерация

Вам может потребоваться выполнить последовательные операции, где результат каждой итерации используется в последующей итерации. Earth Engine предоставляет метод iterate() для таких задач. Помните, что iterate() выполняется последовательно и, следовательно, будет медленным для больших операций. Используйте его только в том случае, если вы не можете использовать map() и фильтры для достижения желаемого результата.

Хорошей демонстрацией использования функции iterate() является создание последовательности чисел Фибоначчи . Здесь каждое число в последовательности является суммой двух предыдущих. Функция iterate() принимает два аргумента: функцию (алгоритм) и начальное значение. Сама функция получает два значения: текущее значение в итерации и результат предыдущей итерации. Следующий пример демонстрирует, как реализовать последовательность Фибоначчи в Earth Engine.

Редактор кода (JavaScript)

var algorithm = function(current, previous) {
  previous = ee.List(previous);
  var n1 = ee.Number(previous.get(-1));
  var n2 = ee.Number(previous.get(-2));
  return previous.add(n1.add(n2));
};

// Compute 10 iterations.
var numIteration = ee.List.repeat(1, 10);
var start = [0, 1];
var sequence = numIteration.iterate(algorithm, start);
print(sequence);  // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

Теперь, когда вы хорошо понимаете концепции JavaScript, вы можете ознакомиться с Учебным пособием по API для ознакомления с геопространственными функциями API Earth Engine.