Add items to array (non-nested) - Google App Script - javascript

JS noob here.
I'm trying to add unique values to an array based on a condition, however each time I'm adding an item to the array it will be nested. How can I add items to an array without nesting them?
var Settings = sp.getSheetByName('Settings');
var email_list = Settings.getRange("D2:D").getValues().filter(String);
var portfolio_list = Settings.getRange("E2:E").getValues().filter(String);
var i;
var distribution_list = [];
for (i = 0; i < email_list.length +1; i++) {
if ((portfolio_list[i] == 'someValue') && (distribution_list.indexOf(email_list[i]) == -1)) {
distribution_list.push(email_list[i]);
}
}
What I've noticed that .push() adds the elements as a nested array. This way I cannot check it with indexOf() because it never returns -1 when it comes to duplicates.
How could I add an item(s) to an array only if it is not present already in array?

Use Array#flat to flatten the 2D array
Use Set to store/get unique values.
Snippet:
const email_list = Settings.getRange(
'D2:D'
) /* Better to limit range ("D2:D"+Settings.getLastRow())*/
.getValues()
.flat() /*Flatten the array*/
.filter(String);
const portfolio_list = Settings.getRange('E2:E')
.getValues()
.flat()
.filter(String);
const distribution_set = new Set();
for (let i = 0; i < email_list.length /*+1 will throw error*/; i++) {
if (
portfolio_list[i] == 'someValue' &&
!distribution_set.has(
email_list[i]
) /*Added, but not needed as set can only contain unique values*/
) {
distribution_set.add(email_list[i]);
}
}
/*Instead of a for-loop, you can also do this:
const dSet = new Set(portfolio_list.filter(e => e === 'someValue'));*/
const distribution_list = [...distribution_set]; /*back to array*/

Related

How to compare an item in an array to all items in other array and add it into shpreadsheet?

I'm developing a tool and currently I'm stuck with a problem.
I'm writing a code in GoogleAppScript (JavaScript) and I have two columns where I collect data. As a result I've two arrays. Let's call them mainArray and checkArray
I need a code doing this logic:
getting the 1st value of the mainArray, i.e. mainArray[0]
chenking the value if it's equal to checkArray[0], then checkArray[1]... checkArray[i]
if there's a match, then toss it to the garbage bin, and swith to the mainArray[1]
Checking mainArray[1] with all of the values from checkArray, as we did it in p.2
If there's no match with any vals from the checkArray add these value into the 3rd array (finArray)
I've done exaclty the opposite.
for (var j=0; j<checkArr.length; j++) {
for(var i=0; i<mainArr.length; i++) {
if(mainArr[i][0]!==''){
if(checkArr[j][0]==mainArr[i][0])
{
Logger.log('not in the list'+mainArr[i][0])
finArr.push(mainArr[i][0])
break;
}}
But I don't know how to get the code working as I described above.
`
// The Arrays actually are one dimensional
// I prefer to create a one dimensional array
// GetDataArray function creates one dimensional array
function GetDataArray(sht,rng) {
var Data = [] var i = 0;
Logger.log(' Sht Name %s\n rng %s,', sht.getName(), rng)
sht.getRange(rng).getValues() .forEach(
function (row) {
row.forEach( function (cell) {
//Logger.log(cell);
Data[i++] = cell }); } );
return Data
} //
......
var sht = SpreadsheetApp.getActiveSheet()
var rngMain = ....// Provide the range
var rngCheck = ...
var checkArr = GetDataArray(sht, rngCheck)
var mainArr = GetDataArray(sht, rngMain)
var finArr = []
mainArr.forEach( function(cell) {
if (cell == '') continue
if (checkArr.indexOf(cell) != -1) finArr.push(cell)})
function thefunc() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet1');
let vs1 = sh.getRange(1,1,sh.getLastRow(),1).getValues().flat();
let vs2 = sh.getRange(1,2,sh.getLastRow(),1).getValues().flat();
let d = 0;
vs1.forEach((r,i) => {
if(~vs2.indexOf(r[0])) {
sh.deleteRow(i+1-d++);//delete row
}
});
}

javascript find matching variables between two nested arrays

I have two nested arrays.
arr1 = [["image1","shirt", "collared",40],["image3","shirt", "buttoned",40]]
arr2 = [["image1","blue"],["image2","red"]]
The desired output is : If the image names (image) match, I want to return the color from the second array to a variable.
I have tried using two for loops:
var color = for (var i = 0; i < arr1.length; i++ ) {
for (var j = 0; j < arr2.length; j++ ) {
if (arr1[i][0] === arr2[j][0]) {
return arr2[j][1]
}
}
Since this is a larger part of a program, The first loop gets executed much before the second loop...however both are nested into each other in the order that I have specified.....I am trying to using the variable to color some html elements, but my entire program gets halted. I am not sure if my approach is right.
Feels like you're trying to use the second array as a lookup into the first. Here's a way to do this by transforming it into an object:
function toLookupTable(shirtColors) {
//keys will be image names, values will be colors
const lookupTable = {};
shirtColors.forEach(shirtColor => {
//use array destructuring
const [ image, color ] = shirtColor;
lookupTable[image] = color;
});
return lookupTable;
}
const colorLookup = toLookupTable( [["image1","blue"],["image2","red"]] );
console.log(colorLookup["image2"]); //outputs "red"
Use Array#reduce and Array#findIndex
I want to return the color from the second array to a variable.
const arr1 = [["image1","shirt", "collared",40],["image3","shirt", "buttoned",40]]
const arr2 = [["image1", "blue"],["image2","red"]]
const res = arr2.reduce((a,[image,color])=>{
if(arr1.findIndex(([n])=>n===image) > -1) a.push(color);
return a;
}, []);
console.log(res);
You can use reduce
let arr1 = [["image1","shirt", "collared",40],["image3","shirt", "buttoned",40]];
let arr2 = [["image1","blue"],["image2","red"]];
let op = arr1.reduce((out,inp,index)=>{
if(arr2[index].includes(inp[0])){
out.push(arr2[index][1])
}
return out
},[] )
console.log(op)

Deleting an item from array by comparing array items

Input array:
["temp/1/Lounge/empty",
"temp/1/Lounge/66,66,66,66,66,66,66,66,64,64,64,64…,64,64,64,64,64,64,64", "temp/2/Lounge/empty",
"temp/3/Lounge/empty"]
I have an array of elements as shown above.
Each item has four parts seperated by ('/').
If first three parts are same and fourth part is different for any two items.I want to remove the item having fourth part as 'empty'.
Example:
If fourth part of element has 'empty' in one item and some data like 66,64,…,64,64,64 in another element.
I want to delete the item having 'empty' as fourth part in the array.
I want output as below:
["temp/1/Lounge/66,66,66,66,66,66,66,66,64,64,64,64…,64,64,64,64,64,64,64",
"temp/2/Lounge/empty",
"temp/3/Lounge/empty"]
I tried to split the array items:
for(i=0;i<arr.length;i++){
stringType = message.split('/')[0];
day = message.split('/')[1] ; //day
room = message.split('/')[2] ;
settingData = message.split('/')[3] ;
}
Please help me to compare items and delete from array.
You can do it as follows:
first, store for every array value in a hash map what "4th values" it has;
next, filter the array and explicitly delete array values of which the 4th value is empty and there are other 4th values (we can check this in the created hash map).
function splitValue(value, ignoreCase) {
let split = value.split('/'),
key = split.slice(0, 3).join('/'),
val = split.slice(3).join('/');
if (ignoreCase) {
key = key.toLowerCase();
}
return [key, val];
}
function filter(arr, ignoreCase = false) {
var byKey = {};
for (let value of arr) {
let [key, val] = splitValue(value, ignoreCase);
if (!byKey.hasOwnProperty(key)) {
byKey[key] = [];
}
if (val !== 'empty') {
byKey[key].push(val);
}
}
return arr.filter((value) => {
let [key, val] = splitValue(value, ignoreCase);
return (val !== 'empty' || byKey[key].length === 0);
});
}
console.log(filter([
"temp/1/Lounge/empty",
"temp/1/Lounge/something",
"temp/2/Lounge/empty",
"temp/3/Lounge/empty"]));
console.log(filter([
"temp/1/Lounge/something",
"temp/3/kitchen/something",
"temp/1/Lounge/empty",
"temp/3/Kitchen/empty"]));
console.log(filter([
"temp/1/Lounge/something",
"temp/3/kitchen/something",
"temp/1/Lounge/empty",
"temp/3/Kitchen/empty"], true));
.as-console-wrapper {
max-height: 100% !important;
}
I also demonstrate in the above example how you can ignore casing of letters, so that temp/3/kitchen/... and temp/3/Kitchen/... are treated as belonging to the same group.
You can use this code. It works perfectly what you need
var resultData = ["temp/1/Lounge/empty", "temp/1/Lounge/66,66,66,66,66,66,66,66,64,64,64,64…,64,64,64,64,64,64,64", "temp/2/Lounge/empty","temp/3/Lounge/empty"];
var data = resultData;
for(var i=0; i<data.length; i++){
var iItem = data[i];
var iFirst = iItem.substring(0, iItem.lastIndexOf("/") + 1);
var iLast = iItem.substring(iItem.lastIndexOf("/") + 1, iItem.length);
for(j=i+1 ; j<data.length; j++){
var jItem = data[j];
var jFirst = jItem.substring(0, jItem.lastIndexOf("/") + 1);
var jLast = jItem.substring(jItem.lastIndexOf("/") + 1, jItem.length);
if(iFirst === jFirst && iLast==='empty'){
resultData.splice(i,1);
}
}
}
console.log(resultData);
You can see that data array is exact copy of resultData array to maintain proper loop when you splice the element from them. For further work around and experimenting the long array values, here is the link to working JSFIDDLE

Find common objects in multiple arrays by object ID

I've searched SO for a way to do this but most questions only support two arrays (I need a solution for multiple arrays).
I don't want to compare exact objects, I want to compare objects by their ID, as their other parameters may differ.
So here's the example data:
data1 = [{'id':'13','name':'sophie'},{'id':'22','name':'andrew'}, etc.]
data2 = [{'id':'22','name':'mary'},{'id':'85','name':'bill'}, etc.]
data3 = [{'id':'20','name':'steve'},{'id':'22','name':'john'}, etc.]
...
I'd like to return all objects whose ID appears in all arrays, and I don't mind which of the set of matched objects is returned.
So, from the data above, I'd expect to return any one of the following:
{'id':'22','name':'andrew'}
{'id':'22','name':'mary'}
{'id':'22','name':'john'}
Thanks
First, you really need an array of arrays - using a numeric suffix is not extensible:
let data = [ data1, data2, ... ];
Since you've confirmed that the IDs are unique within each sub array, you can simplify the problem by merging the arrays, and then finding out which elements occur n times, where n is the original number of sub arrays:
let flattened = data.reduce((a, b) => a.concat(b), []);
let counts = flattened.reduce(
(map, { id }) => map.set(id, (map.get(id) || 0) + 1), new Map()
);
and then you can pick out those objects that did appear n times, in this simple version they'll all come from the first sub array:
let found = data[0].filter(({ id }) => counts.get(id) === data.length);
Picking an arbitrary (unique) match from each sub array would be somewhat difficult, although picking just one row of data and picking the items from that would be relatively easy. Either would satisfy the constraint from the question.
If you want the unique object by Name
data1 = [{'id':'13','name':'sophie'},{'id':'22','name':'mary'}]
data2 = [{'id':'26','name':'mary'},{'id':'85','name':'bill'}]
data3 = [{'id':'29','name':'sophie'},{'id':'22','name':'john'}]
flattened = [ ...data1, ...data2, ...data3 ];
counts = flattened.reduce(
(map, { name }) => map.set(name, (map.get(name) || 0) + 1), new Map()
);
names = []
found = flattened.filter(({ name }) => {
if ((counts.get(name) > 1) && (!names.includes(name))) {
names.push(name);
return true
}
return false
});
its too many loops but , if u can find the common id which is present in all the arrays then it would make your finding easier i think .you can have one array value as reference to find the common id
var global = [];
for(var i = 0;i<data1.length;i++){
var presence = true;
for(var j=0;j<arrays.length;j++){
var temp = arrays[j].find(function(value){
return data1[i].id == value.id;
});
if(!temp){
presence = false;
break;
}
}
if(presence){
global.push(data1[i].id)
}
}
console.log(global);
var data1 = [{'id':'13','name':'sophie'},{'id':'22','name':'andrew'}];
var data2 = [{'id':'22','name':'mary'},{'id':'85','name':'bill'}];
var data3 = [{'id':'20','name':'steve'},{'id':'22','name':'john'}];
var arrays = [data1, data2, data3];
var global = [];
for(var i = 0;i<data1.length;i++){
var presence = true;
for(var j=0;j<arrays.length;j++){
var temp = arrays[j].find(function(value){
return data1[i].id == value.id;
});
if(!temp){
presence = false;
break;
}
}
if(presence){
global.push(data1[i].id)
}
}
console.log(global);
There's mention you you need n arrays, but also, given that you can:
put all the arrays into an array called data
you can:
combine your arrays
get a list of duplicated IDs (via sort by ID)
make that list unique (unique list of IDs)
find entries in the combined list that match the unique IDs
where the count of those items match the original number of arrays
Sample code:
// Original data
var data1 = [{'id':'13','name':'sophie'},{'id':'22','name':'andrew'}]
var data2 = [{'id':'22','name':'mary'},{'id':'85','name':'bill'}]
var data3 = [{'id':'13','name':'steve'},{'id':'22','name':'john'}]
var arraycount = 3;
// Combine data into a single array
// This might be done by .pushing to an array of arrays and then using .length
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort?v=control
var data = [].concat(data1).concat(data2).concat(data3);
//console.log(data)
// Sort array by ID
// http://stackoverflow.com/questions/840781/easiest-way-to-find-duplicate-values-in-a-javascript-array
var sorted_arr = data.slice().sort(function(a, b) {
return a.id - b.id;
});
//console.log(sorted_arr)
// Find duplicate IDs
var duplicate_arr = [];
for (var i = 0; i < data.length - 1; i++) {
if (sorted_arr[i + 1].id == sorted_arr[i].id) {
duplicate_arr.push(sorted_arr[i].id);
}
}
// Find unique IDs
// http://stackoverflow.com/questions/1960473/unique-values-in-an-array
var unique = duplicate_arr.filter(function(value, index, self) {
return self.indexOf(value) === index;
});
//console.log(unique);
// Get values back from data
//https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter?v=control
var matches = [];
for (var i = 0; i < unique.length; ++i) {
var id = unique[i];
matches.push(data.filter(function(e) {
return e.id == id;
}))
}
//console.log(matches)
// for data set this will be 13 and 22
// Where they match all the arrays
var result = matches.filter(function(value, index, self) {
return value.length == arraycount;
})
//console.log("Result:")
console.log(result)
Note: There's very likely to be more efficient methods.. I've left this in the hope part of it might help someone
var arr1 = ["558", "s1", "10"];
var arr2 = ["55", "s1", "103"];
var arr3 = ["55", "s1", "104"];
var arr = [arr1, arr2, arr3];
console.log(arr.reduce((p, c) => p.filter(e => c.includes(e))));
// output ["s1"]

compare 2d array with 1d array in javascript

var player1=["t1", "t9", "t7", "t8", "t2"];
var player2=["t5", "t3", "t4", "t6"];
var winmoves=[[t1,t2,t3],[t4,t5,t6],[t7,t8,t9],[t1,t4,t7],[t2,t5,t8],[t3,t6,t9],[t1,t5,t9],[t3,t5,t7]];
else if (moves>=3 && moves<=9) {
moves+=1;
if (turn==1) {
var i=0;
turn=2;
x.innerHTML="<img src='x.png'/>";
player1.push(x.id);
while(i<=moves){
if (winmoves[i] in player1) {
alert("player1 wins");
document.getElementById("player1").innerHTML=1;
}
i+=1;
}
}
i have 1d array player1 and 2d array winmoves in javascript and i want to check that w[0]'s all values are present in p and so on for w[1],w[2],etc.
if condition with (winmoves[i] in player1) is not working.
i don't know if i am writing this write.
help me guys i am stuck here how can i do so.
It is not working even after i have made these changes.
else if (moves>=3 && moves<9) {
moves+=1;
if (turn==1) {
var i=0;
turn=2;
x.innerHTML="<img src='x.png'/>";
player1.push(x.id);
while(i<=moves){
mapped1 = winmoves.map(a1 => a1.every(e1 => player1.includes(e1)));
if (mapped1[i]) {
alert("player1 wins");
document.getElementById("player1").innerHTML=1;
}
i+=1;
}
}
else if (turn==2) {
turn=1;
var i=0;
x.innerHTML="<img src='o.png'/>";
turn=1;
player2.push(x.id);
while(i<=moves)
{
mapped2 = winmoves.map(a => a.every(e => player2.includes(e)));
if (mapped2[i]) {
alert("player2 wins");
document.getElementById("player2").innerHTML=1;
}
i+=1;
}
}
}
I would simply do this with a simple invention of Array.prototype.intersect() and the rest is such a straightforward single liner.
Array.prototype.intersect = function(a) {
return this.filter(e => a.includes(e));
};
var player1 = ["t1","t2","t3","t5","t7"],
winmoves = [["t1","t2","t3"],["t4","t5","t6"],["t7","t8","t9"],["t1","t4","t7"],["t2","t5","t8"],["t3","t6","t9"],["t1","t5","t9"],["t3","t5","t7"]];
filtered = winmoves.filter(a => a.intersect(player1).length == a.length);
mapped = winmoves.map(a => a.intersect(player1).length == a.length);
console.log(filtered);
console.log(mapped);
OK we have a generic Array method which finds the intersection of two arrays. (inbetween the array it's called upon and the one provided as argument) It's basically a filter checking each item of first array to see whether it is included in the second array. So we filter out the items exist in both arrays.
To obtain the filtered array we utilize Array.prototype.filter() again. This time our first array is winmoves which includes arrays that we will check for each the intersection with player1 array. If the intersection length is equal to winmove's item's length that means all elements of winmove's item is existing in the player1 array. So we return that array item to the filtered.
Specific to your case without using an intersect method you can utilize Array.prototype.every() as follows;
var player1 = ["t1","t2","t3","t5","t7"],
winmoves = [["t1","t2","t3"],["t4","t5","t6"],["t7","t8","t9"],["t1","t4","t7"],["t2","t5","t8"],["t3","t6","t9"],["t1","t5","t9"],["t3","t5","t7"]];
filtered = winmoves.filter(a => a.every(e => player1.includes(e)));
mapped = winmoves.map(a => a.every(e => player1.includes(e)));
console.log(filtered);
console.log(mapped);
What you could do is use nested for loops
for(var j = 0, j < elemInP, j++){
int flag = 0;
for(var x = 0, x < elemInWx, x++){
for(var y = 0, y < elemInWy, y++){
if(p[j] == w[x][y]){
flag = 1;
/*There is no need to run this loop once the value has been found*/
break;
}
}
if(flag){
/*If we have found the value no need to keep looking*/
break;
}
}
if(!flag){
print p[j] is not in w;
}
}
This is just a general idea of one way to compare the two arrays. The actual syntax of the code will need to be edited to work in JavaScript as this is just basic pseudocode. Flag is just a variable that holds if the value was found or not and is reset for each new value. For efficiency, you could have a break/return after setting flag = 1, but this is

Categories

Resources