函式程式設計簡介
Earth Engine 使用平行處理系統,在大量機器上執行運算。為啟用這類處理,Earth Engine 採用函數式語言常用的標準技術,例如參照透明度和延遲評估,大幅提升最佳化和效率。
函式程式設計與程序程式設計的主要差異在於沒有副作用。也就是說,您編寫的函式不會依賴或更新函式以外的資料。如下列範例所示,您可以重新建構問題,以便使用沒有副作用的函式來解決問題,這類函式更適合平行執行。
For 迴圈
不建議在 Earth Engine 中使用 for 迴圈。您可以使用 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 中正確使用 if/else 條件運算子。雖然 API 確實提供 ee.Algorithms.If() 演算法,但強烈建議不要使用,而是採用更實用的方法,使用 map() 和篩選器。Earth Engine 採用
延遲執行,也就是說,運算式的評估作業會延遲到實際需要其值時才進行。在某些情況下,這類執行模型會評估 ee.Algorithms.If() 陳述式的 true 和 false 替代方案。這可能會導致額外的運算和記憶體用量,具體取決於運算式和執行運算式所需的資源。
假設您想解決上述範例的變體,其中工作是只計算奇數的平方。以下示範不使用 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() 的最佳示範是建立費氏數列。在這個數列中,每個數字都是前 2 個數字的總和。iterate() 函式會採用 2 個引數:函式 (演算法) 和起始值。函式本身會傳遞 2 個值,分別是疊代中的目前值,以及前一個疊代的結果。以下範例說明如何在 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 教學課程,瞭解 Earth Engine API 的地理空間功能。