I want to get a range from my sheet. As recommended in Best practices, I am trying to get a array and manipulate it, but I'm confused:
const ss = Spreadsheet.getActive(),
sh = ss.getSheetByName("Sheet1"),
rg = sh.getRange("A1:C1"),//has 1,2,3
values = rg.getValues();
console.log(values);
The logs show
[[1,2,3]]
As you can see I got all three elements. But, when I log the length of the array(array.length), it is just 1(instead of 3). When I test existence of a element using .indexOf or .includes, It says -1 or false.
const values = /*same as logged above*/[[1,2,3]];
console.log(values.indexOf(2));//got -1 expected 1
console.log(values.includes(1));//got false expected true
Why?
I have the same issue with setValues().
rg.setValues([1,2,3]);//throws error
The error is
"The parameters (number[]) don't match the method signature for SpreadsheetApp.Range.setValues."
My specific Question is: What exactly does getValues() return? Is it a special kind of array?
Documentation excerpts:
From The official documentation, getValues() returns
a two-dimensional array of values,
It ALWAYS returns a two dimensional array of values.
One dimensional array is
[1,2,3]
Two dimensional array is
[[1,2,3]]
//or
[[1], [2], [3]]
There is/are array(s) inside a array.
indexed by row, then by column.
It is indexed by row first: i.e., The outer array has rows as inner array. Then each inner array has column elements. Consider the following simple spreadsheet:
A
B
C
1>
1
2
3
2>
2
3
4
3>
3
4
5
A1:A3 contains 3 rows and each row contains 1 column element. This is represented as [[1],[2],[3]]. Similarly, The following ranges represent the following arrays. Try to guess the array structure based on the A1 notation:
A1Notation
Number of Rows
Number of columns
Array Structure
array.length
array[0].length
A1:A3
3
1
[[1],[2],[3]]
3
1
A1:C1
1
3
[[1,2,3]]
1
3
A1:B2
2
2
[[1,2],[2,3]]
2
2
B1:C3
3
2
[[2,3],[3,4],[4,5]]
3
2
A2:C3
2
3
[[2,3,4],[3,4,5]]
2
3
Note how the two dimension provides direction.
See live visualization below:
/*<ignore>*/console.config({maximize:true,timeStamps:false,autoScroll:false});/*</ignore>*/
const test = {
'A1:A3': [[1], [2], [3]],
'A1:C1': [[1, 2, 3]],
'A1:B2': [
[1, 2],
[2, 3],
],
'B1:C3': [
[2, 3],
[3, 4],
[4, 5],
],
'A2:C3': [
[2, 3, 4],
[3, 4, 5],
],
};
Object.entries(test).forEach(([key, value]) => {
console.log(`The range is ${key}`);
console.table(value);
console.info(`The above table's JavaScript array notation is ${JSON.stringify(value)}`)
console.log(`=================================`);
});
<!-- https://meta.stackoverflow.com/a/375985/ --> <script src="https://gh-canon.github.io/stack-snippet-console/console.min.js"></script>
The values may be of type Number, Boolean, Date, or String, depending on the value of the cell.
In the above example, We have Spreadsheet Number type elements converted to JavaScript number type. You can check spreadsheet type using =TYPE(). Corresponding JavaScript type reference is here
Empty cells are represented by an empty string in the array.
Check using
console.log(values[0][0]==="")//logs true if A1 is empty
Remember that while a range index starts at 1, 1, the JavaScript array is indexed from [0][0].
Given the two dimensional array structure, to access a value, two indexes of format array[row][column] is needed. In the above table, if A2:C3 is retrieved, To access C3, Use values[1][2]. [1] is second row in range A2:C3. Note that the range itself starts on second row. So, second row in the given range is row3 [2]is third column C.
Notes:
Warning:
Retrieved values from a range is always two dimensional regardless of the range height or width(even if it is just 1). getRange("A1").getValues() will represent [[1]]
setValues() will accept the same array structure corresponding to the range to set. If a 1D array is attempted, the error
The parameters (number[]/string[]) don't match the method signature for SpreadsheetApp.Range.setValues.
is thrown.
If the array does NOT exactly correspond to the range being set,i.e.,if each of the the inner array's length does not correspond to the number of columns in the range or the outer array's length does not correspond to the number of rows in the range being set, The error similar to the following is thrown:
The number of columns in the data does not match the number of columns in the range. The data has 5 but the range has 6.
Related answers to the above error:
https://stackoverflow.com/a/63770270
Related Search
indexOf/includes uses strict type checking. They won't work when you compare primitives against array objects. You can use Array.flat to flatten the 2D array to a 1D one. Alternatively, Use a plain old for-loop to check something.
const values = [[1,2,3]].flat();//flattened
console.log(values.indexOf(2));//expected 1
console.log(values.includes(1));//expected true
References:
Basic reading
MDN Arrays guide
Related
I would like a function in JavaScript, where I can obtain an array with the corresponding positions of an Array of numbers, where adding their values results in the number that I want to obtain.
New.
I need return only one response, although there are other possible ones.
Although the ideal answer is the longest array.
Example 1:
I have the Array with the following numbers:
[9,4,11,6,3,5,7]
I want to obtain an array where the sum of its values gives me the value 7
Desired response: [1,4]
Example 2:
With the same starting array as Example 1, I want to obtain the value 14
Desired response: [1,4,6]
From already thank you very much.
I need some help finding symmetric difference of a multi dimensional array, and a simple array. The first value in each inner array of the multidimensional array cells is the index that compares to the simple array.
So
array1 = [1,4,6,7]
array2 = [[1,"more",12],[8,"some",12]]
the result should be something like:
compare(array1, array2) = //[4,6,7] // there are three differences when compared this way
compare(array2, array1) = //[8,"some",12] // there is only one difference when compared this way
I need to return an array that has both difference of array1 from array2 AND difference from array2 from array1 in the same format as the lead array.
Ideally these are not overwriting the existing arrays but creates a new with the output results. There won't be other array formats besides these two array formats.
Each compare can use a different function if it helps. You don't have to use the same function for both, but if you can, great.
I tried a few permutations of loop comparisons
Also solutions found here
How to get the difference between two arrays of objects in JavaScript
And of the simple array methods here
How to get the difference between two arrays in JavaScript?
But I just am not being successful. Can someone give me a hand, and also explain their solution? Any modern tools are fine as long as its broadly cross browser compatible. All my other code sticks to ES6, so that would be ideal. If whipping out a one liner solution please explain what is going on so I can learn.
Thanks!
Update # Dave, this made sense to me, but after it failed I started trying different filter methods and other techniques in the posts above, without much success.
let newNurkles = new Array();
for(var i = 0; i < nurkles.length; i++){
if(this.activeNurkles.includes(nurkles[i])){
} else {
newNurkles.push(nurkles[i]);// if not then push to array
}
}
console.warn("Nurkles to Add" + newNurkles);
This shows how to perform a disjunctive union on two arrays, one being single dimensional while the other is a multidimensional array.
The symmetry is determined by each element of the single with the first element of each sub-array in the multi. The multi will only be one level deep.
Uses: Array.prototype.map(), Array.prototype.filter()
Steps:
Map over the first input array
For each element, filter the second input to exclude those found in first input
Limit results to only the first array returned
Notes:
o is the iteration of array1
t is iteration of array2
t[0] represents the match key
t[idx] represents the current value of the sub-array being iterated
Results from array2 will produce a multidimensional array
const array1 = [1, 4, 6, 7];
const array2 = [[1, "more", 12],[8, "some", 12], [7, 3, 9], [2, 7, 5, 4], [4, 3]];
const oneToTwo = array2.map((t, idx) => array1.filter(o => t[idx] !== o))[0]
const twoToOne = array1.map(o => array2.filter(t => o !== t[0]))[0]
console.log(oneToTwo);
console.log(twoToOne)
This question already has answers here:
From array, generate all distinct, non-empty subarrays, with preserved order
(3 answers)
Closed 1 year ago.
Assume I have this array:
const input = [“a”, “b”, “c”, “d”];
I want to create this output:
[
[“a”],
[“a”, “b”],
[“a”, “c”],
[“a”, “d”],
[“a”, “b”, “c”],
[“a”, “b”, “d”],
[“a”, “c”, “d”],
[“a”, “b”, “c”, “d”],
[“b”],
[“b”, “c”],
[“b”, “d”],
[“b”, “c”, “d”],
[“c”],
[“c”, “d”],
[“d”]
]
I don’t care about the order, or the length of the combos, just need all the various ways to uniquely combine the items in the array.
What is the best way to do this in JavaScript? I suspect there’s a beautiful recursive solution, but iterative would work too.
Also, what is the correct technical term for this?
The correct technical term is power set. Here is the canonical recursive form:
const f = (A, i=0) => i == A.length ? [[]] : f(A, i+1).flatMap(x => [x, [A[i]].concat(x)]);
console.log(JSON.stringify(f(['a', 'b', 'c', 'd'])));
Recursive solution probably is the easiest to understand, although I guess there are other more efficient (in terms of computation complexity) solutions too.
First of all, the actual elements in the array do not matter, so that we can just use their indexes (0...n-1) to do the computation, later we convert those indexes into actual elements by actualArray = indexArray.map(i => inputArray[i]). In the discussion below, we assume indexes are stored in the output/result.
Then, since the order in the combination does not matter, and since everything (the index) within the combination must be unique, we can just make sure the indexes in the combinations are always in increasing order.
So, we can start with the combinations (array of arrays) that contain only 1 elements. Without any computation we all know those are:
[[0], [1], [2], [3], ... [n-1]].
We can write code to generate them and use them as the seeds.
Then, for finding out all combinations (array of arrays) containing m+1 elements based on already known combinations (array of arrays) containing m elements, we can do this:
Iterate through all combinations having m elements (array of arrays)
For each combination (array of length m),
Iterate through the range between (inclusive at both ends) combination[combination.length -1] and n - 1 if the range is valid for finding the next index
Make a copy of the original array and append the new index to it. Such as newCombination = [...combination, newIndex]. This is a new combination containing m+1 elements.
Add the newly found combination to the result.
Now we have found all combinations having m+1 elements. They can be used to find all combinations having m+2 elements.
We can do this until we find the last combination, which contains n elements.
To facilitate the algorithm described above, the internal data structure could be:
[
[[0], [1], [2], ..., [n-1]], // indexes of combinations with 1 elements
[[0, 1], [0, 2], ..., [n-2, n-1]], // indexes of combinations with 2 elements
...
[[0, 2, ... n-1]], // indexes of combinations with n elements
]
To verify the correctness, we just need to check these:
Total number of combinations is the same as what we can calculate by math
Within each of the combinations, elements are always in increasing order
There's no duplicated combinations (adding combination.join(',') to a Set could be handy)
BTW, this is just my thoughts, I have not verified it with any real code or data :-)
I have output like this(Multi dimensional array);
(4) [Array(3), Array(2), Array(2), Array(2)]
0: (3) [9, 8, 9]
1: (2) [5, 6]
2: (2) [6, 7]
3: (2) [4, 4]
length: 4
__proto__: Array(0)
I would like to get each value and multiply them and return the value. How do I do that?
First of all you should probably check why the numbers are coming as an array if you need to join them into one number. But, working with what you've given to us...
First, you have to get each inner array and join it as one single number. The best approach I can imagine is casting each number inside to a string, concatenating them, and casting back to Number, like this:
const numbersArray = outerArray
.map(innerArray =>
innerArray.map(number => number.toString()).join(''))
.map(Number)
After having mapped the array, you can then reduce it to a single number, multiplying along the way (and starting at 1 since we don't want an initial value to change the result):
numbersArray.reduce((product, each) => product * each, 1)
myArray = [];
myArray.length;
myArray[1000000] = true;
myArray.length;
why does this return 100001?
ive read this in douglas crockford book and i dont understand what this
means
1000001, you've probably meant. An array is extended as soon as you access its element beyond current bounds. That is why after you touch its element no. 10⁶, it becomes of 10⁶ + 1 elements.
Maybe you check with a smaller index, like 10 and have a look to the values of the array.
The result is a sparse array with missing indices and one value on index 10.
The length is, as always, last index plus one.
var myArray = [];
console.log(myArray.length);
myArray[10] = true;
console.log(myArray.length);
console.log(myArray);
It returns 100001 because,
myArray = []; creates an empty array
That's why myArray.length; = 0
When you do myArray[1000000] = true;
that time actually what happens is it puts all values from 0th index to 999999th index to undefined and then puts you 1000000 value to true. so actually there are 1000001 values in an array.
That's why the length is 1000001
every function of array specifies that array works as a collection of things in a sequence which means you cant put value at random place even if you provide any random index the by the default value (undefined) will be available as a value for other places.
Arrays start at index 0, so if we have an array:
var arr = [1,2,3,4,5];
arr[0] is 1, arr[1] is 2 and so on, and the array's length is 5, because it contains 5 "elements". So, arrays start at index 0 (if you wanted to get the first element of the array, you would have to run arr[0], not arr[1], because arr[1] would be the second element) but .length counts the elements and starts with "1" for the first element, "2" for the second element, etc.
Now when you run this:
var arr = [1,2,3,4,5];
arr[200] = "whatever";
console.log(arr);
You will get this output:
(201) [1, 2, 3, 4, 5, undefined × 195, "whatever"]
So when we randomly added an element to the array at index 200 (which is actually the 201th element in the array, since arrays start at 0, not 1), the array's length just grew from 5 to 201 (the same thing can be seen in the output), and as you can see in the output, the array now contains the original 5 elements (1, 2, 3, 4 and 5), 195 ghost elements whose value undefined when you query them (don't bother what I mean by ghost element just now though), and 1 "whatever" element at its end (the output in the console would be slightly different if you manually inserted the 195 undefined elements, but don't bother yourself with such things for now).
So in your case, an array is defined (myArray), by default, it contains nothing, so it has a length of 0. Then you go on and say "I want to add an element at the 1000000th index of this array" (the line myArray[1000000] = true), don't let the true value of the added element confuse you! the output would be the same regardless of what followed the myArray[1000000] = part, so myArray[1000000] = "whatever" would give you the same output: an array whose length is 1000001. Here is the output of your array when used with console.log(..) (remember, the output would be the same even if "whatever" was inserted in place of true):
(1000001) [undefined × 1000000, true]
Also, remember, the array you get when you say var arr = []; arr[1000] = "foo" is sparse (If you are interested in sparse arrays)
The other comments have answered your question correctly as well but I decided to do so because: 1. I have a bad feeling the true part in myArray[1000000] = true is confusing you. 2. They explained the arrays-start-at-0 thing in a not-too-clear way.