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)
Related
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
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)
I have a group of arrays that I need to filter out duplicates. It needs to work in such a fashion that within each array, there are no duplicates, and within the total group, there are no two arrays that hold the same values.
The first part is easy - for each inner array, I can apply Set to the array and filter it out. So, given the matrix arrays I can apply the following to filter:
const sets : string[][] = arrays.map(arr=>[...new Set(arr)].sort());
This will give me an array of sets. How can I make this into a set of sets? As in, if sets=[[a, b],[c],[d, a],[c],[e]] I would like setOfSets to equal [[a, b],[c],[d, a],[e]]?
Applying setOfSets = [...new Set(sets)]; would not work, since arrays that are equal are not considered equal by default if they have different addresses. Is there a way to force set to check by value, or another effective way to create this effect?
Edit
Original matrix:
[[a, b, b],
[c,c],
[b,a],
[d,a],
[c,c],
[e,e]]
after creating and sorting sets:
[[a,b],
[c],
[a,b],
[d,a],
[c],
[e]]
desired result:
[[a,b],
[c],
[d,a],
[e]]
If the data in your set is easy to serialize, I would opt for a solution like this:
const data = [
["a", "b", "b"],
["c","c"],
["b","a"],
["d","a"],
["c","c"],
["e","e"]
];
// Create the "hash" of your set
const serializeSet = s => Array
.from(s)
.sort()
.join("___");
// Create a map (or object) that ensures 1 entry per hash
const outputMap = data
.map(xs => new Set(xs))
.reduce(
(acc, s) => acc.set(serializeSet(s), s),
new Map()
);
// Turn your Map and Sets back in to arrays
const output = Array
.from(outputMap.values())
.map(s => Array.from(s));
console.log(output);
To come up with a good hash function for your set, you need to have a good look at your data. For example:
When your arrays consist of single characters from a-z, like in my example above, we can sort those strings using a default sorter and then join the result using a character from outside the a-z range.
If your arrays consist of random strings or numbers, JSON.stringify(Array.from(s).sort()) is safer to use
When your arrays consist of plain objects, you could JSON.stringify its sorted elements, but watch out for differences in the order of objects properties! (e.g. {a: 1, b: 2} vs {b: 2, a: 1})
What is the fastest way to make objectIds unique in an Array?
For testing if 2 objectIds are equal, may I convert objectIds to other type, such as numbers or strings?
The easiest way would be to add the ids as keys of an object like this:
var array = [1, 2, 3, 4, 5, 6, 2, 3, 4]
var obj = {}
array.forEach(function(id){obj[id] = true})
array = Object.keys(obj)
Other alternatives would be sorting the array and using binary search and using some data structure like AVL tree.
I found _.groupBy which works on objects by setting the property you want to group by but failed to find one for grouping an array of arrays.
arrays = [[0,'A','01010'],[4,'CD','1111'],[9,'FF','01010'],[6,'AX','01010']]
.groupBy yields nothing. I want to group by the 3rd value in each array.
what if I wanted to group by the 1st and 3rd array value?
_.groupBy() works on arrays or objects and allows you to specify an iterator function.
So this would group by the 3rd value in each array:
_.groupBy(arrays, function(num){return num[2]});
demo fiddle
You could also use the 1st and 3rd values. Exactly how you do that depends on how you want to combine the 2 values. For instance this:
_.groupBy(arrays, function(num){return num[0]+'.'+num[2]});
Results in:
Object {0.01010: Array[1], 4.1111: Array[1], 9.01010: Array[1], 6.01010: Array[1]}
Given your data.
Or if you want to group by the third value and then group those results by the first value we can do this:
var out = _.groupBy(arrays, function(num){return num[2] });
out2={};
for (var prop in out) {
out2[prop] = _.groupBy(out[prop],function(num) {return num[0]});
}
Which, with this data:
arrays = [[0,'A','01010'],[4,'CD','1111'],[9,'FF','01010'],[6,'AX','01010'],[0,'AX','01010']]`
(so that we have a duplicate first entry) produces:
01010: Object 0: Array[2] 6:Array[1] 9: Array[1] 1111: Object 4: Array[1]
demo of that