I have the following Apps Script, which is almost what I'm looking for. What it's doing is getting a list of items from a Google Sheet to populate a Google Form Multiple Choice Question with a list of items. However, it's including all 100 rows, rather than just the ones that have values in them.
What am I missing to make sure it only includes cells that have a len > 1?
function getWorkbookNames(){
var form = FormApp.getActiveForm();
var items = form.getItems();
var ss = SpreadsheetApp.openByUrl(
'spreadsheetnamestringhere');
var sheet = ss.getSheetByName('Unique Databases');
var sheetValues = sheet.getRange("A2:A").getValues();
var values = sheetValues.slice(1);
var names = [];
for(var p = 0; p < values.length; p++){
names.push(values[p][0])
}
var pValues = items[8].asListItem();
pValues.setChoiceValues(names).setRequired(true)
var areas = [];
for (var i = 0; i < values.length; i++) {
areas.push(values[i][1])
}
}
Any help/advice you all could provide would be greatly appreciated.
Solved by adding another filter layer:
function getWorkbookNames() {
var form = FormApp.getActiveForm();
var items = form.getItems();
var ss = SpreadsheetApp.openByUrl(
'spreadsheetnamestringhere');
var sheet = ss.getSheetByName('Unique Databases');
var sheetValues = sheet.getRange("A2:A").getValues();
var filterValues = sheetValues.filter(String);
var values = filterValues.slice(1);
var names = [];
for (var p = 0; p < values.length; p++) {
names.push(values[p][0])
}
var pValues = items[8].asListItem();
pValues.setChoiceValues(names).setRequired(true)
var areas = [];
for (var i = 0; i < values.length; i++) {
areas.push(values[i][1])
}
}
Related
I have a Google Apps Script that pulls and lists all the assignments from Google Classroom within a domain in a Google Sheet, but now I need to pull only certain assignments after a certain date. I must be putting the date or condition wrong, because the array remains empty at the end (whereas if I comment out the if condition with the date filter, the code works perfectly fine and lists all assignments).
The other "non-visible" problem is that the for loop is still going through all of the assignments before applying the filter, which wastes time. The idea would be to have for loop be limited to only the assignments after a certain date from the beginning instead of searching through everything, but I don't know if that is possible.
The code is below.
function listAssignmentsbyDate() {
var s1 = SpreadsheetApp.getActiveSpreadsheet();
var sh = s1.getSheetByName('LA');
var response = Classroom.Courses.list();
var courses = response.courses;
var arr1 = []; var arr2 = []; var arr3 = []; var arr4 = [];
var today = new Date();
var oneWeekAgo = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000);
for (i = 0; i < courses.length; i++) {
var course = courses[i];
var ids = course.id;
var title = course.name;
var state = course.courseState;
arr1.push([ids,title,state]);
}
for (i = 0; i < arr1.length; i++) {
if (arr1[i][2] !== 'ARCHIVED'){
var list = arr1[i][0];
var page = null, t = [];
do {
var tea = Classroom.Courses.CourseWork.list(list, {pageToken: page, pageSize: 100});
page = tea.nextPageToken; var t = t.concat(tea.courseWork);
} while (page);
try {
for (q = 0; q < t.length; q++) {
var c = t[q];
var name = arr1[i][1];
// The line below is what is not working.
if(oneWeekAgo < c.creationTime){
var ti = c.title;
var des = c.description;
var st = c.state;
var link = c.alternateLink;
var typ = c.workType;
var poi = c.maxPoints;
var create = c.creationTime;
var due = c.dueDate;
var duet = c.dueTime;
var cour = c.courseId;
var ids = c.id;
var user = c.creatorUserId;
arr2.push([name,ti,des,st,link,typ,poi,create,due,duet,cour,ids]);
arr3.push(user);
}
}
} catch (e) {continue;}
}
}
for (r=0; r < arr3.length; r++){
try {
var eu = arr3[r];
var us = AdminDirectory.Users.get(eu).primaryEmail;
arr4.push([us]);
} catch(e){continue;}
}
sh.getRange(2, 2, arr4.length, arr5[0].length).setValues(arr4);
sh.getRange(2, 3, arr2.length, arr2[0].length).setValues(arr2);
s1.getSheetByName('CACHE').getRange('B1').setValue('');
}
I have two large arrays in my node application.
var styles = [{itemID:..., styleID:..., styleNum:..., otherFields...}]; // 42455 items
var products = [{productID:..., styleNum:..., otherFields...}]; // 72K items
I need to loop through the products and get the associated styleID from the styles array and add a new item into a new array. The styles array is sorted by styleNum. Here is what I have tried:
var i=0, len = products.length, items = new Array(products.length);
for (i = 0; i < len; i++)
{
var workingItem = products[i];
var styleID = filterStyles(workingItem.styleNum)[0].styleID;
var item = {styleID:..., other fields};
items[i]=item;
}
...
function filterStyles(styleNum)
{
var results = [];
var item;
for (var i = 0, len = createdStyles.length; i < len; i++)
{
item = createdStyles[i];
if (item.styleNum == styleNum) results.push(item);
}
return results;
}
This is very slow, it takes 1 second to iterate over 100 items from my products array. I tried the same using asyc.each, but get the same response time.
When I remove the filter function, it's lighting fast. Is there any way for me to improve my filter function?
To avoid scanning the array every time O(n2), you could create a map keyed by styleNum.
var styleNumMap = Object.create(null);
styles.forEach(function(style) {
if (!styleNumMap[style.styleNum]) {
styleNumMap[style.styleNum] = [];
}
styleNumMap[style.styleNum].push(style);
});
Then you can just do
var i=0, len = products.length, items = new Array(products.length);
for (i = 0; i < len; i++)
{
var workingItem = products[i];
var styleID = styleNumMap[workingItem.styleNum][0].styleID;
var item = {styleID:..., other fields};
items[i]=item;
}
I can't get this function working. It's has to copy all the values of spreadsheet "A" to spreadsheet "B".
function triggerOnTime() {
var SpreadSheetKeyA = "142WNsfQQkSx4BuNhskDM9aXD9ylRHNZh34oO5TBTt1g";
var SpreadSheetKeyB = "1h8fDwCUUPHRdmTHu-5gMyqU294ENZxCZcHCNCuN6r_Y";
var sheet1 = SpreadsheetApp.openById(SpreadSheetKeyA).getActiveSheet();
var sheet2 = SpreadsheetApp.openById(SpreadSheetKeyB).getActiveSheet();
var data = sheet1.getDataRange().getValues();
var array = [];
for (var y = 1; y < data.length; y++) {
for (var x = 0; x < 35; x++){
array.push(data[y][x]);
}
Logger.log(array);
sheet2.appendRow(array);
sheet1.deleteRow(y);
}
}
It now copy's two or three values, but copy them multiple times (random). The function must also delete the copied values from sheetA. But it only deletes the values that are added to sheetB.
EDIT (Updated code)
function triggerOnTime() {
var SpreadSheetKeyA = "142WNsfQQkSx4BuNhskDM9aXD9ylRHNZh34oO5TBTt1g";
var SpreadSheetKeyB = "1h8fDwCUUPHRdmTHu-5gMyqU294ENZxCZcHCNCuN6r_Y";
var sheet1 = SpreadsheetApp.openById(SpreadSheetKeyA).getActiveSheet();
var sheet2 = SpreadsheetApp.openById(SpreadSheetKeyB).getActiveSheet();
var data = sheet1.getDataRange().getValues();
var array = [];
for (var y = 0; y < data.length; y++) {
for (var x = 0; x < 35; x++){
array.push(data[y][x]);
}
sheet2.appendRow(array);
sheet1.deleteRow(y+1);
array = [];
}
}
After playing around a little, I have found a fix for you (albeit a hack, I guess. Im sure there's a better way of doing it)
Whats happening is, on line 14 where you appendRow(array), you are appending the array at it's current state to the second sheet; basically creating a big pyramid of values of your array over time.
If sheet 1 contained something like this:
1,1,1
2,2,2
3,3,3
4,4,4
5,5,5
Your sheet 2 would get this appended:
1,1,1
1,1,1,2,2,2
1,1,1,2,2,2,3,3,3
... and so on.
You could do something like this:
function triggerOnTime() {
var SpreadSheetKeyA = "142WNsfQQkSx4BuNhskDM9aXD9ylRHNZh34oO5TBTt1g";
var SpreadSheetKeyB = "1h8fDwCUUPHRdmTHu-5gMyqU294ENZxCZcHCNCuN6r_Y";
var sheet1 = SpreadsheetApp.openById(SpreadSheetKeyA).getActiveSheet();
var sheet2 = SpreadsheetApp.openById(SpreadSheetKeyB).getActiveSheet();
var data = sheet1.getDataRange().getValues();
var array = [];
for (var y = 1; y < data.length; y++) {
for (var x = 0; x < 35; x++){
array.push(data[y][x]);
}
sheet2.appendRow(array);
sheet1.deleteRow(y);
array = []; //reset the array contents
}
}
The additional line will just reset the array and add the row you want to copy across.
Let me know if this works out for you.
Here's a pseudocode example about what I'm trying to do:
var totalLanguages = XX;
for(var i = 0; i < totalLanguages; i++){
var dynamicArray + i = new Array();
/*.....*/
}
I need to create dynamically many arrays as the value of totalLanguages which can be either number.
This is to be able to do something like this:
for(var i = 0; i < totalLanguages; i++){
var arrayLanguages["es"] = dynamicArray+i;
var arrayLanguages["en"] = dynamicArray+i;
}
Is there any way to do this?
var languageNames = ['en', 'es'];
var languages = {};
for (var i = 0; i < languageNames.length; i++) {
languages[languageNames[i]] = [];
}
You are basically trying to recreate an array with variable names. Just use an Array to start out!
var dynamicArray = [];
for(var i = 0; i < totalLanguages; i++) {
dynamicArray[i] = new Array();
}
You can use multi-dimensional arrays:
var languagesArray = new Array(totalLanguages);
for(var i = 0; i < totalLanguages; i++) {
var innerArray = new Array();
innerArray.push("Hello");
innerArray.push("World");
languagesArray[i] = innerArray;
}
console.log(languagesArray[0][0]);
See: How can I create a two dimensional array in JavaScript?
How about:
for(var i = 0; i < totalLanguages; i++){
window["dynamicvariable " + i] = new Array();
/*.....*/
}
I have the following problem:
var price = ['4','5','8','12']
var produce = ['kiwi','orange','apple','banana']
var stock = ['yes','no','no','yes']
i need to group them so that the end output is on array in the following format:
var store = [ ['4','kiwi','yes'],['5','orange','no'], ...]
im so confused as in how to make one array with these values into a 2d array. thanks
Using JavaScript with some overkill :):
var price = ['4','5','8','12']
var produce = ['kiwi','orange','apple','banana']
var stock = ['yes','no','no','yes']
// if the lengths/size of the above arrays are the same
var store = [];
for(var i = 0, len = price.length; i < len; i++) {
store.push([price[i], produce[i], stock[i]]);
}
// if the lengths/size of the above arrays aren't the same and you want the minimum full entries
var storeMin = [];
for(var i = 0, len = Math.min(price.length, produce.length, stock.length); i < len; i++) {
storeMin.push([price[i], produce[i], stock[i]]);
}
// if the lenghts/size of the above arrays aren't the same and you want the maximum entries with defaulting missing values to null
// replace the nulls by any default value want for that column
var storeMax = [];
for(var i = 0, pLen = price.length, prLen = produce.length, sLen = stock.length, len = Math.max(pLen, prLen, sLen); i < len; i++) {
storeMax.push([pLen>i?price[i]:null, prLen>i?produce[i]:null, sLen>i?stock[i]:null]);
}
var price = ['4','5','8','12']
var produce = ['kiwi','orange','apple','banana']
var stock = ['yes','no','no','yes']
var store = [];
$.each(price,function(ind,elm) {
store.push([elm,produce[ind],stock[ind]]);
});
console.log(store);