Range input to function in Google apps script - javascript

In a cell in my google sheet, I call my function like this: myFunction(A1:A3), where A1 = 5, A2 = 7 and A3 = 3. I now want to loop over the input (A1, A2, and A3) and (for example) sum them.
function myFunction(input) {
if (!input.map) {
return -1;
}
var sum=0
for(var i=0; i<input.length; i++){
sum = sum + parseInt(input[i]);
}
return sum
}
But it only returns the value in A1 (5) because input.length returns 1.
If I remove parseInt(input[i]), it returns "05,7,3"
What am i doing wrong?

Custom function arguments are converted to JavaScript object types. If the parameter is a multicell range, it's converted to an array object which members are arrays, in other words, as a 2D array.
In order to get each cell value, instead of input[i] use something like input[i][j].
Example:
/**
* #customfunction
*/
function mySum(input) {
if (!input.map) return -1;
var sum = 0;
for(var i = 0; i < input.length; i++){
for(var j = 0; j < input[0].length; j++){
sum = sum + parseInt(input[i][j]);
}
}
return sum
}
Note: The above function could be improved by adding some rules / input data validation, like replace blanks by 0.
References
Custom Functions in Google Sheets

there's built functions for do that but if you want to learn how to script and code this is great !
the code works for just vertical ranges e.g (A1:A5) but in horizontal/square ranges wont, just do another loop inside the first one to do sum of 2D array
for(var i=0; i<input.length; i++){
for(var j=0; j<input[0].length; j++){
sum = sum + parseInt(input[i][j]);
}
}

Related

Create array with function javascript

I need to create function that creates and returns array. Its size needs to match the rows parameter, and each next element contains consecutive integers starting at 1. To call this function I need to use argument 5. Here below is what I wrote so far. Can you tell me what's wrong here?
function createArray(rows) {
for(let i = 1; i < rows.length; i++) {
console.log(rows[i]);
}return rows;
}
createArray(5);
You need to create an array and return it, whereas you return just rows which is a number. The idea of using a for loop is the best way to go. In that loop you just need to set the values in the array accordinlgy.
Another problem in your code is that rows is of type number and does have a property length but that does not have the desired value. So we just use rows in the for loop. We start the loop with i = 0 because array indices start at 0.
Code
function createArray(rows) {
let arr = new Array(rows);
for (let i = 0; i < rows; i++) {
arr[i] = i + 1;
}
return arr;
}
console.log(createArray(5));
We can not use length property for number. create an empty array and then push values into that array until required size is achieved.
function createArray(rows) {
var arr = [];
for(let i = 1; i <= rows; i++) {
arr.push(i);
}return arr;
}
createArray(5);
I think what you want is createArray(5) return [1,2,3,4,5] if that's the case you could do this
function createArray(rows) {
const arr = []
for(let i = 1; i <= rows; i++) {
arr.push(i);
}
return arr;
}
console.log(createArray(5));
The problem is, that rows.length is not available on 5, because 5 is a number.
You have to use an array as parameter:
Array(5) creates an array with the length of 5 and fill("hello") fills this array with "hello" values.
function createArray(rows) {
for (let i = 1; i < rows.length; i++) {
console.log(rows[i]);
}
return rows;
}
const rows = Array(5).fill("hello");
createArray(rows);
I don't know, if this is the behaviour you want, if not, I misunderstood your question.

How do you do Numpy.eye in JavaScript?

How to create the np.eye function in JavaScript? Or what would be the numpy.eye equivalent in JavaScript?
I would like a function that creates the "Identity matrix" in 2d dimensions, and you can change the number of rows, columns and the index of the diagonal.
https://numpy.org/devdocs/reference/generated/numpy.eye.html
This doesn't take care of M,N,k
#Andy
function eye(n){
var t=[];
for(var i=0;i<n;i++){
var p=[]
for(var j=0;j<n;j++){
p.push(j==i?1:0)
}
t.push(p)
}}
This doesn't take care of M,N,k
You are almost there, just have to put the extra parameters there, like the outer loop (rows) runs to N, the inner loop (columns) runs to M, and the comparison would be j-i===k:
function eye(N,M,k) {
var t = [];
for (var i = 0; i < N; i++) {
var p = []
for (var j = 0; j < M; j++) {
p.push(j - i === k ? 1 : 0)
}
t.push(p)
}
return t;
}
let NMk=prompt("N,M,k").split(",").map(x=>parseInt(x));
console.log(eye(...NMk).map(x=>x.join()));
Try entering something like 3,3,0 ("classic") or 2,3,1 (a "fancy" one) when asked.
(And don't worry about the snippet printing strings, that's just the join() , to keep output small, and without much coding).

Three Number Sum - Finding triplets that sum to target

Write a function that takes in a non-empty array of distinct integers and a target integer.
Your function should find all triplets in the array that sum up to the target sum and return a two-dimensional array of all these triplets.
Each inner array containing a single triplet should have all three of its elements ordered in ascending order
ATTEMPT
function threeNumberSum(arr, target) {
let results = [];
for (let i = 0; i < arr.length; i++) {
let finalT = target - arr[i];
let map = {};
for (let j = i+1; j < arr.length; j++) {
if (map[arr[j]]) {
results.push([arr[j], arr[i], map[arr[j]]]);
} else {
map[finalT-arr[j]] = arr[j];
}
}
}
return results;
}
My code is formatted all funny, but right now im not getting any output. Am I missing a console log somewhere or something?
Your problem is that you read input wrong.
Pay attention to the last part of question: How to Read Input that is Used to Test Your Implementation
You wrote a function that takes the array as first arg and the target integer as the second one. But the input is entered one by one, so your program should read one value at a time from the console input.

How to loop through all possible pairs of JSON object keys exactly once?

Say that I have a data structure of n elements and a function check(element1, element2) which performs some kind of checkup on two elements. I need to check exactly all possible pairs of elements. Using combinatorics it is easy to deduce that we need to perform exactly 'n choose 2' binomial coefficient iterations ( n*(n-1)/2 iterations)
So if my data structure is an array, the following nested loops would work:
for(let i = 0; i < elements.length; i++) {
for(let j = i + 1; j < elements.length; j++) {
check(elements[i], elements[j]);
}
}
This way we check the first element with all the others, the second element with elements 3 to n (since we already checked it with the first one), the third with elements 4 to n and so on and so forth. However if 'elements' was a JSON where the key to each element is not an integer, how can we achieve this effect? Obviously we can ensure that we perform all checkups with the following code:
for(var key1 in elements) {
for(var key2 in elements) {
if(key1 != key2) {
check(elements[key1], elements[key2]);
}
}
}
However obviously we are doing a lot of checkups more than once resulting in n^2 iterations.
What method can I use to achieve the same result as in the example with the array?
If you put all the keys you're going to be looping into an array using Object.keys() then you can use your standard for loop to "skip" over previously seen keys like so:
const keys = Object.keys(elements);
for(let i = 0; i < keys.length; i++) {
const key1 = keys[i];
for(let j = i + 1; j < keys.length; j++) {
const key2 = keys[j];
check(elements[key1], elements[key2]);
}
}
Perhaps you could get the list of keys in an array:
let elements = { a: 1, b: 2, c: 3 };
let keys = Object.keys(elements).sort(); // Sorts the keys array alphabetically, and thus simulating the numbers example and be sure you're not repeating "lower" order key after passing it
for(let i = 0; i < keys.length; i++) {
for(let j = i + 1; j < keys.length; j++) {
// check(elements[keys[i]], elements[keys[j]]);
console.log(elements[keys[i]], elements[keys[j]])
}
}
output:
1 2
1 3
2 3

How to shuffle characters in a vertical inverted pattern?

I have a string "ABCDEFGHIJKLMN" that I need to shuffle in a specific manner. To do that, I write the characters sequentially in columns bottom -> top and then left -> right (4 chars per column for example) until all characters are done. If the last column is not complete, then the empty spaces need to be on the bottom (this is very important). Like so:
D H L N
C G K M
B F J
A E I
The shuffle is accomplished by producing a new string reading the block of letters as we read text, in rows left -> right:
"DHLNCGKMBFJAEI"
The cases where the columns are not complete (word.size % column_height !=0) complicate things considerably.
I came up with a few solutions, but I'm not sure if there is a simpler (ie, shorter OR easier to read) and more elegant way of coding this problem. My solutions either have an ugly, separate block of code to handle the final incomplete column or seem way too complicated.
My question is, could it be done better?
If you don't want any spoilers and decide to try and figure it out for yourself, stop reading now. If you want to work from what I fiddled so far, then a working piece of code is
var result = "";
var str = "ABCDEFGHIJKLMN";
var nr_rows = 4;
var current_row = 4;
var columns = Math.floor(str.length / nr_rows);
var modulus_table = str.length % nr_rows;
var modulus_position = -1;
for (var i = 0; i < nr_rows; i++) {
for (var j = 0; j < columns; j++) {
result += str[current_row + j * nr_rows - 1];
}
if (modulus_table > 0) {
result += str[str.length + modulus_position];
modulus_table--;
modulus_position--;
}
current_row--;
}
console.log(result);
Moving on to arrays, the next example would loop through each character, placing it correctly in a matrix-like array, but it doesn't work. The array needs to be created another way. For another example of this issue, see How to create empty 2d array in javascript?. This would also need an ugly hack to fix the last characters on the last incomplete column aligning to the bottom instead of the top.
var result = [[],[]];
var str = "ABCDEFGHIJKLMN";
var nr_rows = 4;
var row = nr_rows - 1;
var column = 0;
for (var i = 0; i < str.length; i++) {
result[row][column] = str[i];
row--;
if (row < 0) {
row = nr_rows;
column++;
}
}
console.log(result);
This last method goes full matrix array, but it quickly becomes complicated, since it needs to loop through the array in 3 different directions. First, create a dummy array with the characters in the wrong place, but where the 'undefined' positions correspond to those that should be left empty. That is acomplished by populating the array 'rotated 90ยบ' from the reading orientation.
Without this first step, the empty positions would be stacked at the bottom instead of the top.
A second pass is required to re-write the caracters in the correct places, skipping any holes in the matrix using the 'undefined' value. This check is made for every position and there is no separate block of code to handle an incomplete last line.
A third pass then reads every character in order to form the final shuffled string. All this seems way too complicated and confusing.
// matrix populated top->bottom and left->right
// with the characters in the wrong place
// but the undefined postions in the correct place of the empty positions
var matrix = [];
var str = "ABCDEFGHIJKLMN";
var rows = 4;
var columns = Math.ceil(str.length / rows);
var k = 0;
for (var i = 0; i < rows; i++) {
matrix[i] = [];
for (var j = columns - 1; j >= 0; j--) {
matrix[i][j] = str[k];
k++;
}
}
// populate the matrix with the chars in the correct place and the 'undefined' positions left empty
var k = 0;
for (var i = 0; i < rows; i++) {
for (var j = 0; j < columns; j++) {
if (matrix[i][j] != undefined) {
matrix[i][j] = str[k];
k++;
}
}
}
// read matrix in correct direction and send to string, skipping empty positions
var result = "";
for (var j = columns - 1; j >= 0; j--) {
for (var i = 0; i < rows; i++) {
if (matrix[i][j] != undefined) {
result += matrix[i][j];
}
}
}
console.log(result);
What if you just split/reverse the array into column groups, and convert to rows?
const result = str.match(/.{1,4}/g) // split string into groups of 4
.map(i => i.split('').reverse()) // reverse each group (bottom to top, and solves the last col issue)
.reduce((res, col) => { // reduce the groups into rows
col.forEach((c, i) => res[i] += c) // concat each string char to the right row
return res
}, ['','','','']) // initialise empty strings per row
.join('') // join the rows up
Fiddle here
If you wish to return a string, I don't see why any intermediate result should use an array when it doesn't have to. The following could use one less array, but it's convenient to use split and an array to control the while loop rather than mutate the string.
The idea is to fill the strings from the bottom up until the column is full, then keep adding from the bottom of each column until it runs out of characters to assign. The row to start filling from is based on how many characters are left and how many rows there are.
Rather than building strings, it could build arrays but then generating a string requires multiple joins.
It can also produce results where there are insufficient slots for all the characters, so a result using 9 characters from 10 or more using a 3x3 "matrix" (see last example).
function verticalShuffle(s, rows, cols) {
var result = [''];
s = s.split('');
while (s.length && result[0].length < cols) {
for (var i = (rows < s.length? rows : s.length) -1 ; i>=0; i--) {
if (!result[i]) result[i] = '';
result[i] += s.splice(0,1)[0] || '';
}
}
return result.join('');
}
var s = 'ABCDEFGHIJKLMN';
console.log(verticalShuffle(s, 4, 4)); // DHLNCGKMBFJAEI
console.log(verticalShuffle(s, 6, 3)); // FLNEKMDJCIBHAG
// Only use 9 characters
console.log(verticalShuffle(s, 3, 3)); // CFIBEHADG
This uses plain ed3 functionality that will run in any browser. I don't see the point of restricting it to ECMAScript 2015 or later hosts.
If interpret Question correctly, you can use for loop, String.prototype.slice() to to populate arrays with characters of string. Use Array.prototype.pop() within recursive function to get last element of array until each array .length is 0.
To create array
[
["D","H","L","N"],
["C","G","K","M"],
["B","F","J"],
["A","E","I"]
]
from vertically inverted string you can use for loop, String.prototype.slice() to set array of arrays containing elements having .length 4, or 3 once .length of parent array is 2, having been set with two arrays containing four elements
var str = "ABCDEFGHIJKLMN";
function fnVerticalInvert(str, arr, res) {
if (!arr && !res) {
arr = []; res = "";
}
if (str) {
for (var i = 0; i < str.length; i += 4) {
arr.push([].slice.call(str.slice(i, i + 4)));
}
}
for (var i = 0; i < arr.length; i++) {
if (arr[i].length) {
res += arr[i].pop()
}
}
if (arr.some(function(curr) {return curr.length}))
return fnVerticalInvert(null, arr, res);
for (var i = 0, l = 4, j = 0, n = l - 1, k; i < l; i++, j += l) {
if (i === l / 2) k = j;
arr[i] = [].slice.call(res.slice(!k ? j : k, !k ? j + l : k + n));
if (k) k += n;
}
return {str: res, arr:arr};
};
var res = fnVerticalInvert(str);
console.log(res);

Categories

Resources