Данная статья является продолжением статьи Бесконечные Зависимые Выпадающие Списки в Google Sheets (часть 3).
Здесь рассмотрен пример практического применения Бесконечных связанных списков при составлении Личного Финансового Плана.
Помимо добавления нескольких удобных для пользователя функций (автоматическая вставка даты внесения платежа и формулы для ведения баланса приходов-расходов) скрипт, приведённый содержит целый ряд существенных доработок и улучшений:
// global variable
const excludedSheets = ['Summary', 'Category'];
const dataSheet = 'Category';
var colShift = 3;
var rowMin = 4;
function onEdit(e) {
let row = e.range.getRow();
let col = e.range.getColumn();
let sheetName = e.source.getActiveSheet().getName();
if (excludedSheets.includes(sheetName)) return;
let name = e.value;
let oldName = e.oldValue;
let sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
let mask = JSON.stringify(sh.getRange(row, colShift+1, 1, col-colShift).getValues()[0]);
let colMax = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(dataSheet).getLastColumn();
if(name !== oldName && row >= rowMin && col < colMax+colShift) {
insertDateFormulasAndDataValidation(row, col, sheetName)
fillColumn(row, col, mask, sheetName);
}
}
function insertDateFormulasAndDataValidation(row, col, sheetName) {
if (col == colShift+1) {
let sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
let dateValue = sh.getRange(row, 2).getValue();
if (dateValue == '') {
let today = new Date();
let timeZone = Session.getScriptTimeZone();
let todayStr = Utilities.formatDate(today, timeZone, 'dd.MM.yyyy');
sh.getRange(row, 2).setValue(todayStr);
};
let formulaStr = '=I' + (row-1) + '+H' + row + '-C' + row;
sh.getRange(row, 9).setFormula(formulaStr);
let conN = String.fromCharCode(65+colShift)
let adress = sheetName + '!' + conN + (row+1) + ':' + conN + (row+3);
sh.getRange(adress).setDataValidation(SpreadsheetApp.newDataValidation()
.setAllowInvalid(false)
.requireValueInRange(sh.getRange(dataSheet+'!$A$2:$A'), true)
.build());
}
}
function tmp() {
insertDateFormulasAndDataValidation(7, 4, 'Transactions');
}
function onOpen() {
let ui = SpreadsheetApp.getUi();
// Or DocumentApp or FormApp.
ui.createMenu('Custom Menu')
.addItem('Create sheets', 'createSheets')
.addToUi();
}
function fillColumn(row, col, mask, sheetName) {
let col_data = col - colShift;
// clear dataVal and Value
let sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
let colMax = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(dataSheet).getLastColumn();
sh.getRange(row, col + 1, 1, colMax-col_data).clearDataValidations().clearContent();
// find date
let sd = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(dataSheet);
let arrData = sd.getDataRange().getValues();
let arrData_2 = [];
let iMax = arrData.length - 1;
for(let i=1; i<=iMax; i++) {
if(JSON.stringify(arrData[i].slice(0, col_data)) == mask) {
arrData_2.push(arrData[i].slice(0, col_data+1));
}
}
arrData_2 = arrData_2.map(item => item.pop())
let uniqArrDate_2 = arrData_2.filter(uniqValues);
// add dataVal
col++;
sh.getRange(row, col).setDataValidation(SpreadsheetApp.newDataValidation()
.setAllowInvalid(false)
.requireValueInList(uniqArrDate_2, true)
.build());
}
function uniqValues(item, index, arr) {
return arr.indexOf(item) === index;
}
Дополнительную информацию вы можете получить из этого видео:
Скрипт, представленный ниже, позволяют автоматически находить и выгружать информацию об объявлениях на одной из бирж фриланса.
Имя домена берётся со страницы Google Spread Sheets. Туда же выгружаются результаты поиска.
В качестве управляющего скрипта используется функция scraper(), которая содержит два цикла. В первом цикле (for-цикл) идёт обращение к веб-страницам сайта, и их сохранение в переменной html. Во втором цикле (while-цикл) идёт последовательная обработка этой переменной с помощью трёх вспомогательных функций:
function scraper() {
const ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1');
const urlDomain = ss.getRange(1, 1).getValue();
let url = urlDomain;
let count = 0;
for (let page = 1; page < 5; page++) {
url = urlDomain + page + '/';
if (page == 1) url = urlDomain;
let response = UrlFetchApp.fetch(url);
ss.getRange(2, 1).setValue(response.getResponseCode());
let html = response.getContentText();
let p = 0;
while (true) {
let out = getBlock(html, 'div', html.indexOf('class="JobSearchCard-primary"', p));
let block = out[0];
p = out[1] + 1;
if (p == 0) break;
let title1 = getBlock(block, 'div', 0)[0];
let title = getBlock(title1, 'a', 0)[0];
let link = getOpenTag(title1, 'a', 0);
link = getAttrName(link, 'href', 0)
let formula = '=HYPERLINK("https://www.freelancer.com' +link + '", "' + title + '")';
ss.getRange(3 + 3 * count, 2).setValue(formula);
let price = getBlock(block, 'div', block.indexOf('class="JobSearchCard-primary-price'))[0];
if (price.includes('span')) price = deleteBlock(price, 'span', price.indexOf('span'));
ss.getRange(3 + 3 * count + 1, 2).setValue(price).setHorizontalAlignment('right');
let description = getBlock(block, 'p', block.indexOf('class="JobSearchCard-primary-description"'))[0];
ss.getRange(3 + 3 * count, 1, 3).mergeVertically().setValue(description)
.setBorder(true, true, true, true, null, null, '#000000', SpreadsheetApp.BorderStyle.SOLID)
.setVerticalAlignment('middle')
.setWrapStrategy(SpreadsheetApp.WrapStrategy.WRAP);
ss.getRange(3 + 3 * count, 2, 3).setBorder(true, true, true, true, null, null, '#000000', SpreadsheetApp.BorderStyle.SOLID);
let cat = getBlock(block, 'div', block.indexOf('class="JobSearchCard-primary-tags"'))[0];
cat = cat.split('</a>').map(item => item.split('>')[1]);
cat.pop();
cat = cat.join(', ');
ss.getRange(3 + 3 * count + 2, 2).setValue(cat);
count++;
};
};
}
function getAttrName(html, attr, i) {
let idxStart = html.indexOf(attr +'=' , i);
if (idxStart == -1) return "Can't to find attr " + attr + ' !';
idxStart = html.indexOf('"' , idxStart) + 1;
let idxEnd = html.indexOf('"' , idxStart);
return html.slice(idxStart,idxEnd).trim();
}
function getOpenTag(html, tag, idxStart) {
let openTag = '<' + tag;
let lenOpenTag = openTag.length;
// where we are?
if (html.slice(idxStart, idxStart + lenOpenTag) != openTag) {
idxStart = html.lastIndexOf(openTag, idxStart);
if (idxStart == -1) return "Can't to find openTag " + openTag + ' !';
};
// begin loop after openTag
let idxEnd = html.indexOf('>', idxStart) + 1;
if (idxStart == -1) return "Can't to find closing bracket '>' for openTag!";
return html.slice(idxStart,idxEnd).trim();
}
function deleteBlock(html, tag, idxStart) { // delete opening & closing tag and info between them
let openTag = '<' + tag;
let lenOpenTag = openTag.length;
let closeTag = '</' + tag + '>';
let lenCloseTag = closeTag.length;
let countCloseTags = 0;
let iMax = html.length;
let idxEnd = 0;
// where we are?
if (html.slice(idxStart, idxStart + lenOpenTag) != openTag) {
idxStart = html.lastIndexOf(openTag, idxStart);
if (idxStart == -1) return ["Can't to find openTag " + openTag + ' !', -1];
};
// begin loop after openTag
let i = html.indexOf('>') + 1;
while (i <= iMax) {
i++;
if (i === iMax) {
return ['Could not find closing tag for ' + tag, -1];
};
let carrentValue = html[i];
if (html[i] === '<'){
let closingTag = html.slice(i, i + lenCloseTag);
let openingTag = html.slice(i, i + lenOpenTag);
if (html.slice(i, i + lenCloseTag) === closeTag) {
if (countCloseTags === 0) {
idxEnd = i + lenCloseTag;
break;
} else {
countCloseTags -= 1;
};
} else if (html.slice(i, i + lenOpenTag) === openTag) {
countCloseTags += 1;
};
};
};
return (html.slice(0, idxStart) + html.slice(idxEnd, iMax)).trim();
}
function getBlock(html, tag, idxStart) { // <tag .... > Block </tag>
let openTag = '<' + tag;
let lenOpenTag = openTag.length;
let closeTag = '</' + tag + '>';
let lenCloseTag = closeTag.length;
let countCloseTags = 0;
let iMax = html.length;
let idxEnd = 0;
// where we are?
if (html.slice(idxStart, idxStart + lenOpenTag) != openTag) {
idxStart = html.lastIndexOf(openTag, idxStart);
if (idxStart == -1) return ["Can't to find openTag " + openTag + ' !', -1];
};
// change start - will start after openTag!
idxStart = html.indexOf('>', idxStart) + 1;
let i = idxStart;
while (i <= iMax) {
i++;
if (i === iMax) {
return ['Could not find closing tag for ' + tag, -1];
};
let carrentValue = html[i];
if (html[i] === '<'){
let closingTag = html.slice(i, i + lenCloseTag);
let openingTag = html.slice(i, i + lenOpenTag);
if (html.slice(i, i + lenCloseTag) === closeTag) {
if (countCloseTags === 0) {
idxEnd = i - 1;
break;
} else {
countCloseTags -= 1;
};
} else if (html.slice(i, i + lenOpenTag) === openTag) {
countCloseTags += 1;
};
};
};
return [html.slice(idxStart,idxEnd + 1).trim(), idxEnd];
}
Более продробную информацию вы сможете найти в этом видео:
В примерах, приведённых ниже, подробно рассматриваются JavaScript и Apps Script методы поиска элементов массивов : find(), findIndex(), indexOf(), lastIndexOf(), includes(), every() и some().
Методы findIndex(), indexOf() и lastIndexOf() позволяют найти индекс массива, удовлетворяющий заданному условию, а метод find() позволяет найти его значение.
Метод includes() удобен для использования в операторе if , поскольку возвращает true, если элемент найден, и false, если нет.
Метод every() проверяет соответствие ВСЕХ элементов массива указанному в callback функции условию, а метод some() проверяет, удовлетворяет ли этому условию ХОТЯ БЫ ОДИН элемент массива.
const arr = [1, 2, 3, 4, 5, 3];
// find() returns the VALUE of the FIRST item satisfies condition of the callback function
// OR return <underfined>
let valueGteater3 = arr.find(item => item > 3);
console.log(valueGteater3); // 4
let valueGteater5 = arr.find(item => item > 5);
console.log(valueGteater5); // undefined
// findIndex() returns the INDEX of the FIRST item satisfies condition of the callback function
// OR return <-1>
let indexItemGteater3 = arr.findIndex(item => item > 3);
console.log(valueGteater3); // 3
let indexItemGteater5 = arr.findIndex(item => item > 5);
console.log(valueGteater5); // -1
// variant for not first item
let notFirstItem = arr.find((item, index) => {
if (item > 3 && index > 3) return true;
});
console.log(notFirstItem); // 5
// indexOf() returns the INDEX of the FIRST item is equal the specified value
// OR return <-1>
let valueEqual3 = arr.indexOf(3);
console.log(valueEqual3); // 2
let valueEqual3Next = arr.indexOf(3, 3);
console.log(valueEqual3Next); // 5
let valueEqual1 = arr.indexOf(1, 3);
console.log(valueEqual1); // -1
// lastIndexOf() returns the INDEX of the LAST item is equal the specified value
// OR return <-1>
let valueEqual3Last = arr.lastIndexOf(3);
console.log(valueEqual3Last); // 5
let valueEqual3NextLast = arr.lastIndexOf(3, 4);
console.log(valueEqual3NextLast); // 2
let valueEqual5Last = arr.lastIndexOf(5, 3);
console.log(valueEqual5Last); // -1
// const arr = [1, 2, 3, 4, 5, 3];
// includes() returns TRUE is element is icluded in the array, and FALSE is not
let isIncludes3 = arr.includes(3);
console.log(isIncludes3); // true
let isIncludes6 = arr.includes(6);
console.log(isIncludes6); // false
// every() returns TRUE if ALL elements satisfy the condition, and FALSE is not
let allPositive = arr.every(item => item > 0);
console.log(allPositive); // true
let moreThen1 = arr.every(item => item > 1);
console.log(moreThen1); // false
// some() returns TRUE if AT LEAST ONE element satisfy the condition, and FALSE is not
let moreThen4 = arr.some(item => item > 4);
console.log(moreThen4); // true
let moreThen5 = arr.some(item => item > 5);
console.log(moreThen5); // false
Более продробную информацию вы сможете найти в этом видео:
Метод .reduce() как и большинство других методов, использующих callback функцию, представляет собой цикл for, внутри которого callback функция последовательно обрабатывает все элементы массива. Однако, следует добавить, что что это единственный метод, который используе ещё один параметр - accumulator (аккумулятор), блягодаря чему метод .reduce() часто используется для вычислений суммы массива.
Метод .reduce() может передавать в callback функцию 4 параметра:
Этот метод может быть использован и для более сложных вычислений. Например, ниже приводится скрипт, который создаёт массив индексов элементов массива arr, представлящих собой нечётные числа.
const arr = [1, 2, 3, 4, 5];
// sum with for loop
let sumArr = 0;
for (let i = 0; i < arr.length; i++) {
sumArr += arr[i];
};
console.log(sumArr);
// sum with forEach method
let sumArr_1 = 0;
arr.forEach(item => sumArr_1 += item);
console.log(sumArr_1);
// sum with reduce method
let sumArr_2 = arr.reduce((acc, item) => acc + item, 0);
console.log(sumArr_2);
// with initial value
sumArr_2 = arr.reduce((acc, item, index, array) => {
console.log(`acc = ${acc}, item = ${item}, index = ${index}`);
return acc + item;
}, 0);
console.log(sumArr_2);
// without initial value
sumArr_2 = arr.reduce((acc, item, index, array) => {
console.log(`acc = ${acc}, item = ${item}, index = ${index}`);
return acc + item;
});
console.log(sumArr_2);
// find indexes items that are odd numbers
let newArr = arr.reduce((acc, item, index) => {
if (item % 2 !== 0) acc.push(index);
return acc;
}, []);
console.log(newArr); // [ 0, 2, 4 ]
// reduceRight
sumArr_2 = arr.reduceRight((acc, item, index, array) => {
console.log(`acc = ${acc}, item = ${item}, index = ${index}`);
return acc + item;
});
console.log(sumArr_2);
Дополнительную информацию вы можете найти в этом видео:
Метод .forEach() , по сути, представляет собой цикл for, внутри которого callback функция последовательно обрабатывает все элементы массива.
Метод .forEach() может передавать в callback функцию три параметра:
Это, пожалуй, единственный метод, который ничего не возвращает. Поэтому используется для внешних обработок, например, для вывода элементов массива на печать.
В частности, в последнем примере с помощью методов .forEach() и .includes() создаётся новый массив result, который содержит в себе общие элементы массивов arr1 и arr2, то есть является результатом пересечения этих массивов.
const arr = [1, 2, 3, 4, 5];
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]);
};
// variant #1
arr.forEach(function(item) {
console.log(item);
});
// variant #2
arr.forEach(item => console.log(item));
console.log('------------------------------------');
// callback function parameters
arr.forEach((item, idx, array) => console.log(item, idx, array));
console.log('------------------------------------');
// get intersection of arrays
let arr1 = [1, 3, 5];
let arr2 = [1, 2, 3, 4, 5];
let result = [];
let res = arr1.forEach(item => {
if (arr2.includes(item)) return result.push(item);
});
console.log(result); // [ 1, 3, 5 ]
console.log(res); // undefined
Дополнительную информацию вы можете найти в этом видео:
Метод .filter() последовательно сравнивает все элементы массива с условием фильтра, указанным в callback функции (функции обратного вызова). То есть метод, по сути, представляет собой цикл for, внутри которого callback функция последовательно обрабатывает все элементы массива.
Метод .filter() может передавать в callback функцию три параметра:
Для того, чтобы элемент, удовлетворяющий условию фильтра, был выбран, callback функция должна вернуть значение true.
Все элементы, для которых callback функция вернула знечение true, собираются в отдельный массив, который может быть сохранён в новом массива (в примерах ниже это массив result2).
В трёх вариантов примера, представленных ниже (examples #1, #2, #3) рассмотрено одно и то же условие фильтра - отобрать все элементы массива со значением > 3.
В последнем примере (наиболее оптимальным с точки зрения краткости кода) логическое выражение, вместо оператора if , поставлено непосредственно в return . Поскольку, как известно, логическое выражение может принимать только 2 значения: true или false.
const arr = [1, 2, 9, 4, 1, 6, 5];
let result = arr.filter((item, idx, arr) => console.log(item, idx, arr));
// [20-06-15 14:53:21:082 EEST] 1 0 [ 1, 2, 9, 4, 1, 6, 5 ]
// [20-06-15 14:53:21:084 EEST] 2 1 [ 1, 2, 9, 4, 1, 6, 5 ]
// [20-06-15 14:53:21:085 EEST] 9 2 [ 1, 2, 9, 4, 1, 6, 5 ]
// [20-06-15 14:53:21:086 EEST] 4 3 [ 1, 2, 9, 4, 1, 6, 5 ]
// [20-06-15 14:53:21:087 EEST] 1 4 [ 1, 2, 9, 4, 1, 6, 5 ]
// [20-06-15 14:53:21:089 EEST] 6 5 [ 1, 2, 9, 4, 1, 6, 5 ]
// [20-06-15 14:53:21:090 EEST] 5 6 [ 1, 2, 9, 4, 1, 6, 5 ]
console.log(result);
// [20-06-15 14:53:21:091 EEST] []
// variant #1
let result2 = arr.filter(item => {
if (item > 3) {
return true;
} else {
return false;
};
});
// variant #2
result2 = arr.filter(item => {
return item > 3;
});
// variant #3
result2 = arr.filter(item => item > 3);
console.log(result2); // [ 9, 4, 6, 5 ]
var sf = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
let data = sf.getDataRange().getValues().slice(1);
console.log(data);
// [ [ '', false, 'apples', 5 ],
// [ '', true, 'carrots', 12 ],
// [ '', false, 'grapes', 4 ],
// [ '', false, 'plums', 3 ],
// [ '', true, 'strawberry', 9 ],
// [ '', false, 'perches', 4 ],
// [ '', false, 'bananas', 1 ] ]
let newData = data.filter(item => item[1]);
console.log(newData);
// [ [ '', true, 'carrots', 12 ],
// [ '', true, 'strawberry', 9 ] ]
И ещё одни полезный скрипт, который не вошёл в это видео - скрипт, который фильтрует ТОЛЬКО уникальные значения.
Идея очень проста: для каждого элемента массива находится его индекс и сравнивается с текущим индексом значения этого элемента в массиве. Если элемент не встретился ранее, то значения индексов будут равны, и функция uniqValue вернёт true .
В первом примере, для лучшего понимания алгоритма, функция uniqValue написана отдельно. Во втором - непосредственно "встроена" в метод .filter
let arrayNotUniq = [1, 5, 9, 5];
//variant #1
function uniqValues(item, index, arr) {
return arr.indexOf(item) === index;
}
let arrayUniq = arrayNotUniq.filter(uniqValues) // [1, 5, 9]
//variant #2
let arrayUniq = arrayNotUniq.filter((item, index, arr) => {
return arr.indexOf(item) === index;
}); // [1, 5, 9]
Дополнительную информацию вы можете найти в этом видео:
Метод .map() последовательно перебирает все элементы массива. То есть, по сути, представляет из себя цикл for, где переменная цикла изменяется от индекса первого элемента до последнего.
Этот метод может передавать в callback функцию 3 элемента:
В примере #1 приводится умножение кажного элемента массива на 2. То есть callback функция каждый раз возвращает элемент массива, умноженный на 2.
В примере #2 проводится исследования параметров метода. Поэтому callback функция ничего не возращет, а только выводит на печать передаваемые её параметры. В каждом цикле это: значение элемента массива, его индекс и сам массив.
var arr = [1, 2, 3];
// example #1
var arr2 = arr.map(x => x * 2); // [ 2, 4, 6 ]
// example #2
var arr2 = arr.map((x, y, z) => {
console.log(x + "|" + y + "|" + z);
});
// 1|0|1,2,3
// 2|1|1,2,3
// 3|2|1,2,3
Скрипты, представленные ниже, обрабатывают один и тот же массив двумя способами:
1.) с помощью цикла for
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var arrM = ss.getRange(1, 1, 10).getValues(); // [[10. Will Smith: $35 million], [9. Paul Rudd: $41 million], [8. Chris
var arrW = ss.getRange(14, 1, 10).getValues(); // [[10. Ellen Pompeo: $22 million], [9. Charlize Theron: $23 million], [8.
var arr = arrM.concat(arrW);
for (var i = 0; i < arr.length; i++) {
arr[i][0] = arr[i][0].replace(":", "").replace("$", "").replace(" (tie)", "(tie)").replace(" Jr", "Jr"); //
arr[i] = arr[i][0].split(' '); // [10., Will, Smith, 35, million]
arr[i][1] = arr[i][1] + " " + arr[i][2]; // [10., Will Smith, Smith, 35, million]
arr[i].splice(2, 1); // [10., Will Smith, 35, million]
if (i < 10) {
arr[i][3] = 'man';
} else {
arr[i][3] = 'woman';
};
};
arr.sort(function(a, b) {
return b[2] - a[2];
});
for (var i = 0; i < arr.length; i++) {
arr[i][0] = i + 1;
Logger.log(arr[i]);
};
ss.getRange(2, 6, arr.length, arr[0].length).setValues(arr);
2.) и с помощью метода .map():
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var arrM = ss.getRange(1, 1, 10).getValues(); // [[10. Will Smith: $35 million], [9. Paul Rudd: $41 million], [8. Chris
var arrW = ss.getRange(14, 1, 10).getValues(); // [[10. Ellen Pompeo: $22 million], [9. Charlize Theron: $23 million], [8.
var arr = arrM.concat(arrW);
var arr2 = arr.map(x => x[0].replace(":", "").replace("$", "")
.replace(" (tie)", "(tie)").replace(" Jr", "Jr")
.split(' ')); // [ [ '10.', 'Will', 'Smith', '35', 'million' ],
arr = arr2.map(x => [x[2], x[1] + ' ' + x[2], x[3], x[4]]);
arr = arr.map((x, i) => {
(i < 10) ? x[3] = 'man' : x[3] = 'woman' ;
return x;
}); // [ [ 'Smith', 'Will Smith', '35', 'man' ],
arr.sort((a, b) => a[0].localeCompare(b[0])); // [ [ '1.', 'Dwayne Johnson', '89.4', 'man' ],
arr = arr.map((x, i) => {
x[0] = i + 1;
return x;
});
console.log(arr);
ss.getRange(2, 6, arr.length, arr[0].length).setValues(arr);
Дополнительную информацию вы можете найти в этом видео:
Прежде чем перейти к рассмотрению метода .sort, необходимо хотябы несколько слов сказать о функциях, используемых в JavaScript и Google Apps Script.
Higher-order functions (Функции более высокого порядка) - называются функции, использующие в качестве аргументов и/или возвращаемых объектов функции первого класса. (Пример - функция .sort)
First-class functions (Функции первого класса) используются в качестве аргументов и/или возвращаемых объектов для функций более высокого порядка. (Пример - функции, являющиеся аргументами для функции .sort)
const arr = [1, 2, 3, 10, 20];
// ========== Higher-order functions ===============
//arr.sort(sortFunction)
// ========== First-class functions ================
// function definition
function twoTimes(x) {
return x * 2;
};
// another function definition
var twice;
twice = function(x) {return x * 2};
// arrow function
twice = (x) => x * 2;
// arrow function with 1 argument
twice = x => x * 2;
console.log(twice(3));
console.log(typeof twice);
// 1.) function as argument another function
var fourTimes = (x, twice) => twice(x);
console.log(fourTimes(3, twice)); // 6
// 2.) return function
var fourTimes = (x) => x * 4;
var xTimes = (x, order) => {
if (x / order == 4) {
return fourTimes;
} else if (x / order == 2) {
return twice;
};
};
var y = xTimes(12, 3); // 8
console.log(y(2)); // =6
console.log('y is ' + typeof y); // y is function
// numbers sorting
const arr = [1, 2, 10, 20];
arr.sort((a, b) => a - b); // [ 20, 10, 2, 1 ]
arr.sort((a, b) => b - a); // [ 1, 2, 10, 20 ]
// string sorting
const arr1 = ['a', 'b', 'A', 'B', 'г', 'Г', 'д', 'Д'];
arr1.sort(); // [ 'A', 'B', 'a', 'b', 'Г', 'Д', 'г', 'д' ]
arr1.sort((a, b) => a.localeCompare(b)); // [ 'a', 'A', 'b', 'B', 'г', 'Г', 'д', 'Д' ]
arr1.sort((a, b) => b.localeCompare(a)); // [ 'Д', 'д', 'Г', 'г', 'B', 'b', 'A', 'a' ]
// 2-dimensional array
var arr_2 = [[1, 5, 6],
[3, 7, 9],
[9, 2, 1]];
arr_2.sort((a, b) => b[1] - a[1]); // [ [ 3, 7, 9 ],
// [ 1, 5, 6 ],
// [ 9, 2, 1 ] ]
// JSON objects
var actors = [
{name: 'Dwayne Johnson', income: 89.4},
{name: 'Chris Hemsworth', income: 76.4},
{name: 'Robert DowneyJr.', income: 66},
{name: 'Akshay Kumar', income: 65},
{name: 'Jackie Chan', income: 58},
];
actors.sort((a, b) => a.income - b.income);
//[ { name: 'Jackie Chan', income: 58 },
// { name: 'Akshay Kumar', income: 65 },
// { name: 'Robert DowneyJr.', income: 66 },
// { name: 'Chris Hemsworth', income: 76.4 },
// { name: 'Dwayne Johnson', income: 89.4 } ]
actors.sort((a, b) => a.name.localeCompare(b.name));
// [ { name: 'Akshay Kumar', income: 65 },
// { name: 'Chris Hemsworth', income: 76.4 },
// { name: 'Dwayne Johnson', income: 89.4 },
// { name: 'Jackie Chan', income: 58 },
// { name: 'Robert DowneyJr.', income: 66 } ]
Дополнительную информацию вы можете найти в этом видео:
Массивы в Apps Script можно создать несколькими способами:
function createArray() {
// ======== HOW TO CREATE ARRAY? ===========
// 1.) Write
var arr = [1, 2, 3];
// 2.) Read from spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var arr1 = ss.getDataRange().getValues(); // [[1.0, 2.0, 3.0]]
// 3.) Using string splitting
var string = 'I am learning Google Spreadsheet';
var arr2 = string.split(' '); // [I, am, learning, Google, Spreadsheet]
// 4.) Using string splitting
var arr3 = 'word'.split(''); // [w, o, r, d]
}
Добавлять элементы в массив можно разными способами:
Если максимальное значение индекса будет превышено более, чем на единицу, то всем элементы между старым и новым максимальными индексами автоматически присваивается значение null.
Значение удаляемого элемнта можно при этом присвоить новой переменной.
function addDeleteItems() {
// ================ ADD ITEMS =======================
// 1.) [index]
var arr4 = [1, 2, 3];
arr4[3] = 4; // [1.0, 2.0, 3.0, 4.0]
arr4[5] = 6; // [1.0, 2.0, 3.0, 4.0, null, 6.0]
arr4[-1] = 0; // [1.0, 2.0, 3.0, 4.0, null, 6.0]
// 2.) .push(value)
arr4.push(7); // [1.0, 2.0, 3.0, 4.0, null, 6.0, 7.0]
// 3.) .unshift(value)
arr4.unshift(0) // [0.0, 1.0, 2.0, 3.0, 4.0, null, 6.0, 7.0]
// ================= DEL ITEMS ======================
// 4.) .pop()
var x = arr4.pop(); // [0.0, 1.0, 2.0, 3.0, 4.0, null, 6.0]
// 5.) .shift()
var x = arr4.shift(); // [1.0, 2.0, 3.0, 4.0, null, 6.0]
// ===== ADD (INSERT), DELETE, CAHGE =================
// 6.) .splice(index, hawManyDelete, whatInsert)
arr4.splice(4, 0, 5); // [1.0, 2.0, 3.0, 4.0, 5.0, null, 6.0]
arr4.splice(5, 1); // [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]
// ============ CHANGE ORDER =========================
// 7.) .reverse()
arr4.reverse(); // [6.0, 5.0, 4.0, 3.0, 2.0, 1.0]
// 8.) .sort()
arr4 = [6.0, 5.0, 404.0, 41.0, 4.0, 3.0, 2.0, 1.0];
arr4.sort();
}
Больше информации и примеров вы сможете найти в этом видео: