Reputation: 135
I'm still getting my head around Apps Script and just need some help editing an array.
So I have two arrays:
var arrayBig = SpreadsheetApp.getSheetByName('Big').getDataRange().getValues();
var arraySmall = SpreadsheetApp.getSheetByName('Small').getDataRange().getValues();
And I want to replace specific rows in arrayBig
based on values in arraySmall
, and then write that array back to my spreadsheet (the last part I'm ok with).
The two arrays have the same number of columns, but arraySmall
has fewer rows.
The rows to replace:
arraySmall
replace that row in arrayBig
.So if the value in Column 1 = 3 replace row number 3 in arrayBig
with the contents of the row from arraySmall
where Column 1 = 3.
I think the answer has to do with the map method but I don't understand it. Just some pointers to get me started would be much appreciated, thank you.
Upvotes: 1
Views: 1609
Reputation: 14537
Just in case. Another solution:
var arrayBig = [ [1,"A","B"], [2,"C","D"], [3,"E","F"], [4,"G","H"] ];
var arraySmall = [ [1,"P","Q"], [3,"Y","Z"] ];
var obj = {}; // it will be { "1":[1,"P","Q"], "3": [3,"Y","Z"] }
arraySmall.forEach( x => obj[x[0]] = x );
arrayBig = arrayBig.map( x => obj[x[0]] || x );
console.log(arrayBig); // [[1,"P","Q"], [2,"C","D"], [3,"Y","Z"], [4,"G","H"]];
It converts the small array into an object where first element of every row is a key and the row is its value. Then it loops through the big array and tries to get values of the object by keys (a first cell). If the key exists the row will replace, if key doesn't exist the for wont change.
Sequence of the rows in the small array doesn't matter as well.
Updage
You can use an array instead of an object if you want:
var arrayBig = [ [1,"A","B"], [2,"C","D"], [3,"E","F"], [4,"G","H"] ];
var arraySmall = [ [1,"P","Q"], [3,"Y","Z"] ];
var arr = [];
arraySmall.forEach( x => arr[x[0]-1] = x ); // [ [1,"P","Q"], [], [3,"Y","Z"], [] ];
arrayBig = arrayBig.map( (x,i) => arr[i] || x);
console.log(arrayBig);
I think it will take more memory, but it works. But you need to be sure that first cells contain numbers only, since they're using as indexes of the array (indexes of array should be numbers, unlike keys that can be anything). And rows of first array should be sorted and has no skipped numbers (1, 2, 3, 4, etc). So, it's a more fragile solution. Just for educational purposes.
Upvotes: 1
Reputation: 22012
Here is one "get you started" approach:
You describe your data, but you do not provide any concrete samples - so here is my starting data, making some assumptions based on the information in the question:
var arrayBig = [ [1, "A", "B"], [2, "C", "D"], [3, "E", "F"], [4, "G", "H"] ];
var arraySmall = [ [1, "P", "Q"], [3, "Y", "Z"] ];
With the above data, the expected outcome is the following, where rows 1 and 3 are replaced:
[ [1, "P", "Q"], [2, "C", "D"], [3, "Y", "Z"], [4, "G", "H"] ];
Here is the approach:
var arrayBig = [ [1, "A", "B"], [2, "C", "D"], [3, "E", "F"], [4, "G", "H"] ];
var arraySmall = [ [1, "P", "Q"], [3, "Y", "Z"] ];
var mapper = new Map();
arraySmall.forEach((row) => {
mapper.set(row[0], row);
} );
newArrayBig = [];
arrayBig.forEach((row) => {
if ( mapper.has( row[0] ) ) {
newArrayBig.push( mapper.get( row[0] ) );
} else {
newArrayBig.push( row );
}
} );
console.log( newArrayBig );
This assumes you have an iron-clad guarantee that there are never more rows of data in arraySmall
than there are in arrayBig
. You can (and should) add some logic to test for that, for more robust code.
Notes
The Map
object (not the map()
method) is central to this approach. This object provides a lookup structure: an index value, pointing to a data value:
var mapper = new Map();
arraySmall.forEach((row) => {
mapper.set(row[0], row);
} );
In our case, the index is the number in the first cell of each arraySmall
row. And the value it points to is the complete data array for that row, for example:
1 -> [1, "P", "Q"]
3 -> [3, "Y", "Z"]
We can now use this lookup data as we iterate through each row of our arrayBig
data:
arrayBig.forEach((row) => { ... } );
The logic inside this forEach
iterator basically says: If the map contains an array using the same number as the current arrayBig
row, then use the arraysmall
data. Otherwise, use the arrayBig
data.
The newArrayBig.push()
method adds that array to our results array.
You can then write this back to your spreadsheet, as needed.
Upvotes: 1