Use of regEx with multiple categories - google-classroom

I need to rotate the match through variables Cat1 to Catx as long as there is data for the Cat'x'. Whenever I do this this, it does not consider as a variable but the literal Cat4 or Cat5 instead of the variable Cat4 & Cat5 when I try to compile the new category label. Such as the following with i increasing until there is no value to the variable searched for .. i.e. Cat57 has nothing assigned.
category = "Cat"+i
This is the portion of my code I believe that needs to be adjusted .. essentially based on the category I am going to assign it a specific column in my spreadsheet (this part hasn't been added yet) .. still stuck on the matching through multiple categories
if(studentmarks && studentmarks.length > 0 && assign.maxPoints > 0){
for (d = 0; d < studentmarks.length; d++){
var marks = studentmarks[d];
if(student.userId == marks.userId){
var ss = SpreadsheetApp.openByUrl(url).getSheetByName(shet);
var re = RegExp(Cat1);
if (assign.title.match(re))
ss.appendRow([category, assign.title, marks.assignedGrade,
assign.maxPoints]);

As we have talked in the comments there is no need to actually use RegEx in this case.
Just define an array and iterate through. Without the need
// Define new array
var Cat = [];
//
// Do stuf to populate Cat array
//
//Access your data
for(var i = 0; i < Cat.length; i++){
var element = Cat[i];
}

Related

office script - range find - return row or array to power automate

I have been trying several different ways to write an office script to search for a value in a cell and return the row or rows to power automate.
I believe I need to use range.find in order to make use of the "completematch: true" option.
However, I have also tried a filter and a foreach loop to find rows which include the text I am searching for.
I'm after a hint as to which method might be best?
essentially trying to:-
power automate - pass text parameter to the script
Scripts search for a match in excel business spreadsheet
the script finds match(s)
Script passes back the row(s) to powerautomate as an array
this is what I have so far: essentially it just finds the row number in which the matching result is found. This seems to work better to avoid partial matched (as happened with the filter method )
any pointers, most welcome
function main(workbook: ExcelScript.Workbook, siteNameToFilter: string) {
let activeSheet = workbook.getActiveWorksheet();
let range = activeSheet.getUsedRange();
let values = range.getValues();
/**
* This script searches for the next instance of the text "Fino" on the current worksheet.
*/
// Get the next cell that contains "Fino".
let findCell = range.find("Fino", {
completeMatch: true, /* Don't match if the cell text only contains "fino" as part of another string. */
matchCase: false,
searchDirection: ExcelScript.SearchDirection.forward /* Start at the beginning of the range and go to later columns and rows. */
});
// Set focus on the found cell.
findCell.select();
// Remove the "TK" text value from the cell, as well as any formatting that may have been added.
//tkCell.clear(ExcelScript.ClearApplyTo.all);
let row = findCell.getRow().getUsedRange();
let ur = findCell.getUsedRange();
console.log(row);
}
I think Find may only be returning the first match. It sounds like you want all matches with the siteName. To do this, you'd either want to filter the range or loop through it.
Here's an example that loops through the range and adds the values from the rows containing the site name to an array. After the loop's completed, the array containing the values is returning by the function:
function main(workbook: ExcelScript.Workbook, siteNameToFilter: string) {
let activeSheet = workbook.getActiveWorksheet();
let range = activeSheet.getUsedRange()
let values = range.getValues() as string[][];
let rowCount = range.getRowCount()
let colCount = range.getColumnCount()
let colIndex = range.getColumnIndex()
let rowsArr: string[][][] = []
for (let i = 0; i < rowCount; i++) {
for (let j = 0; j < colCount; j++) {
if (values[i][j] === siteNameToFilter) {
rowsArr.push(activeSheet.getRangeByIndexes(i, colIndex, 1, colCount).getValues() as string[][])
}
}
}
return rowsArr
}

Google Spreadsheet Loop & IF statement: Loop through co-worker list and add them to a rotation schedule

EDIT - SOLVED
I have to make a rotation schedule for coworkers for the next year. Some coworkers have standard days off and I do not want to schedule them on those days.
This is the manual outcome I would like to get.
Example: Consultant A does not work on mondays, so I do not want Consultant A to be added to the schedule on a monday.
I then want consultant B to be added to the schedule as a fill-up. Consultant A would be next in line on a tuesday etc. Next would be consultant C but consultant C does not work on wednesdays. Therefore, we need to take consultant D for wednesday and consultant C on a thursday, and so on. When we are at the last consultant of the F column, it needs to start again at consultant A.
I have tried all kinds of formulas, like if statements and arrayformula. But there is no way that I know of to loop through the F column just with formulas.
I am not sure if this is at all clear what I want to achieve here, I am stuck 😄
I am using additionally an add-on to send the schedule to everyone's agenda, thats also the reason why i'd love to automate this, because it would help me SO much.
I did try myself on some coding, but I am no coder and I am not sure if it would be helpful at all to share my failure 😄 But this is what I've tried so far:
function Loop() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var EndRow = ss.getLastRow();
for (var i = 2; i <= EndRow; i++) {
var Day = ss.getRange(i,2).getValue();
var Consultants = ss.getRange(i,6).getValue();
var Off = ss.getRange(i,7).getValue ();
var Count = ss.getRange(i,8).getValue();
if(Day == Off){
ss.getRange(i, 3).setValue(Consultants)
}else{
ss.getRange(i, 3).setValue(Consultants)
}
}
}
EDIT:
I found a way without using apps scripts, costs me some more work manually and first tried it with a shorter team list.
The highlighted yellow cells are the cells in which the day off was identical to the work-day cell. So they got switched.
I did have to copy paste my input list of consultants but if this is the only manual way, its fine :)
Try this:
Code:
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName("Sheet1");
var dayCol = sh.getRange("B2:B343").getValues().flat(); //get day column values and convert it to 1d array
var dayOffCol = sh.getRange("G2:G9").getValues().flat(); //get day off values and convert it to 1d array
var dayOffColCopy; //initialize copy
var consCol = sh.getRange("F2:F9").getValues().flat(); //get consultants values or column F
var consColCopy; //initialize copy
var tempArray = []; //storage of final value for column C
for(var i = 0; i < dayCol.length; i++){ //loop through dayCol values
var ctr = (i % consCol.length); //used modulo as counter. the value will return to 0 if the value of i is divisible to the length of consCol or in example 8
//The if statement below will help up reset the value of
//consColCopy and dayOffColCopy once the values are emptied because of the splice()
if(ctr == 0){
consColCopy = consCol.slice();
dayOffColCopy = dayOffCol.slice();
}
//the loop below will get the first non-matching values of dayCol and dayOffColCopy,
//the first non-matching values will be removed to the copy variables using splice()
//and insert it to tempArray using push()
for(var j = 0; j < dayOffColCopy.length; j++){ //loop through dayOffColCopy values
if(dayCol[i] != dayOffColCopy[j]){
tempArray.push(consColCopy.splice(j, 1));
dayOffColCopy.splice(j, 1);
break; //exit loop
}
}
}
sh.getRange(2, 3, tempArray.length, 1).setValues(tempArray); //set the values of temp array to column C
}
Example Data & Output:
Note: Make sure to use the cell that has data in your range and change the sheet name. I also added comments in my code to explain the process.
References:
Array.prototype.push()
Array.prototype.slice()
Array.prototype.splice()
Class Range

For loop to check values from two spreadsheets

I have two spreadsheets:
Column A on sheet 6th&7thRoster lists all IDs in a sample, contains 853 items.
Column C on sheet alreadySubmitted contains the IDs of users who've completed a task. Contains 632 items.
I'm trying to parse through both columns. If a user from Column A of sheet 6th&7thRoster matches a user from Column C of sheet sandboxAlreadySubmitted, I want to write the word "Yes" on Column I of the current row of sheet 6th&7thRoster. When using the code below, I'm not seeing not seeing any instances of the word "Yes" on Column I of 6th&7thRoster, even though I know there's multiple places where that should be the case.
function checkRoster() {
var mainSheet = SpreadsheetApp.openById('XXXXXXX');
var roster = mainSheet.getSheetByName('6th&7thRoster');
var submissions = mainSheet.getSheetByName('alreadySubmitted');
var rosterLastRow = roster.getLastRow();
var submissionsLastRow = submissions.getLastRow();
var rosterArray = roster.getRange('A2:A853').getValues();
var submissionsArray = submissions.getRange('C2:C632').getValues;
var i;
var x;
for (i = 1; i < 853; i++) {
for (x = 1; x < 632; x++){
if (rosterArray[i] == submissionsArray[x]){
roster.getRange(i, 9).setValue("Yes");
}
}
}
}
Feedback on how to solve and achieve this task will be much appreciated. For confidentiality, I cannot share the original sheets.
You want to compate the values of A2:A853 of 6th&7thRoster and C2:C632 of alreadySubmitted.
When the values of C2:C632 of alreadySubmitted are the same with the values of A2:A853 of 6th&7thRoster, you want to put Yes to the column "I".
If my understanding is correct, how about this modification? Please think of this as just one of several possible answers.
Modified script:
function checkRoster() {
var mainSheet = SpreadsheetApp.openById('XXXXXXX');
var roster = mainSheet.getSheetByName('6th&7thRoster');
var submissions = mainSheet.getSheetByName('alreadySubmitted');
var rosterLastRow = roster.getLastRow();
var submissionsLastRow = submissions.getLastRow();
var rosterArray = roster.getRange('A2:A853').getValues();
var submissionsArray = submissions.getRange('C2:C632').getValues(); // Modified
// I modified below script.
var obj = submissionsArray.reduce(function(o, [v]) {
if (v) o[v] = true;
return o;
}, {});
var values = rosterArray.map(function([v]) {return [obj[v] ? "Yes" : ""]});
roster.getRange(2, 9, values.length, values[0].length).setValues(values);
}
Flow:
Retrieve values from A2:A853 of 6th&7thRoster and C2:C632 of alreadySubmitted.
Create an object for searching the values from the values of alreadySubmitted.
Create the row values for putting to 6th&7thRoster.
References:
reduce()
map()
If I misunderstood your question and this was not the direction you want, I apologize.

Concatenating objects in a For loop

I am wanting to perform the concatenation as shown below in the objConcat variable but for X number of objects. Sometimes I'll need to concatenate two objects, and sometimes I'll need to concatenate 50 objects.
How can I iterate this in a For loop where I don't have to manually create these individual object variables?
The importData() function returns an object.
var obj1 = importData(0);
var obj2 = importData(1);
var obj3 = importData(2);
var objConcat = obj1.concat(obj2).concat(obj3);
You could get the first data and save it in a variable. Then, loop through the rest and concatenate each of it to the initial variable.
var objConcat = importData(0);
var n = 50;
for (var i=1; i<n; i++) {
objConcat = objConcat.concat(importData(i));
}

How to populate the table dynamically and correctly with Ajax?

I have a form where the user submits a query and then have a Servlet that processes this query and returns the results in XML. With this result trying to populate a table dynamically via Ajax, for such, I use the following code below.
var thead = $("<thead>");
var rowsTHead = $("<tr>");
var tbody = $("<tbody>");
var numberOfColumns;
$(xml).find("head").each(function(){
var variable = $(this).find("variable");
numberOfColumns = variable.length;
for (var i = 0; i < variable.length; i++){
var name = $(variable[i]).attr("name");
rowsTHead.append($("<th>").html(name));
}
});
thead.append(rowsTHead);
$(xml).find("result").each(function(){
var literal = $(this).find("literal");
var rowsTBody = $("<tr class=\"even\">");
literal.length = numberOfColumns;
for (var j = 0; j < literal.length; j++){
var tdBody = $("<td>");
tdBody.html($(literal[j]).text());
rowsTBody.append(tdBody);
}
tbody.append(rowsTBody);
});
$(".tablesorter").empty()
.append(thead)
.append(tbody);
This code works perfectly until it was used in a UNION query. When using a UNION the returned xml comes in the following way http://pastebin.com/y7hXK1Zy
As can be observed, this query has 4 variables that are: gn1, indication1, gn2, indication2.
What is going wrong is that the values of all the variables being written in columns corresponding to gn1 and indication1.
What I wish I was to write the value of each variable in its corresponding column. I wonder what should I change in my code to make this possible.
You need to respect the name values of the binding elements, and relate them back to the columns that you correctly built from parsing the element. When you are doing the find "literal", you are skipping the parsing of the binding elements. You should find "binding", respect the name and look up which column to use based on that, and then for each of those, find the "literal" elements for the actual values.

Resources