using an average function in Qualtrics - javascript

I'm trying to write a function to compute an average of embedded data. I piped the fields in, parse them (they are numbers with decimals, so I can use parseInt). Then I need to check if any of the values are zero, so I filter it. I then want to average the data points that are left over.
Qualtrics.SurveyEngine.addOnload(function()
{
var a = "${e://Fields/a}"
var b = "${e://Fields/b}"
var c = "${e://Fields/c}"
var a= parseFloat(a)
var b= parseFloat(b)
var c= parseFloat(c)
var all_values;
var all_values= [a, b, c];
function isnonzero(value) {
return value != 0;
}
var filter_it;
var filter_it = all_values.filter(isnonzero);
function avg(filter_it){
var sum = 0;
for (var i = 0; i < filter_it.length; i++) {
sum += parseFloat(arr[i])
}
return average= sum / i;
}
Qualtrics.SurveyEngine.setEmbeddedData("total",average);
I don't think my function is right, or the way I tried to get the info out of the function. Any help would be awesome!

You have a couple of problems here, first, you don't need to re-initialize a variable after it has been defined. Second, you never call your avg() function. And third, you can't use the value of i outside of the for loop. YOu also never define arr in the avg() function. And you don't define average outside the avg function Try the following:
Qualtrics.SurveyEngine.addOnload(function()
{
var a = "${e://Fields/a}"
var b = "${e://Fields/b}"
var c = "${e://Fields/c}"
a= parseFloat(a)
b= parseFloat(b)
c= parseFloat(c)
var all_values= [a, b, c];
function isnonzero(value) {
return value != 0;
}
var filter_it;
filter_it = all_values.filter(isnonzero);
function avg(filter_it){
var sum = 0;
for (var i = 0; i < filter_it.length; i++) {
sum += parseFloat(filter_it[i])
}
return sum / filter_it.length;
}
var average = avg(filter_it);
Qualtrics.SurveyEngine.setEmbeddedData("total",average);
});

Related

Return multiple strings from function based on variable number

I have a string
var str = 'string'
I have a multiplier
var mult = 3
I want to return stringstringstring
The mult will change. Basically mult is kind of like a power but this is a string not a number. And I need to return multiple strings. I'm thinking of looping where mult = the number of times to loop and each would conceptually 'push' but I don't want an array or something like =+ but not a number. I'm thinking I could have the output push to an array the number of times = to mult, and then join the array - but I don't know if join is possible without a delimiter. I'm new at javascript and the below doesn't work but it's what I'm thinking. There's also no ability to input a function in the place I'm running javascript and also no libraries.
var loop = {
var str = 'string'
var arr = [];
var mult = 3;
var i = 0
for (i = 0, mult-1, i++) {
arr.push('string'[i]);
}
}
var finalString = arr.join(''); // I don't know how to get it out of an object first before joining
Not sure if what I want is ridiculous or if it's at all possible
You mean something like below,
var str = 'string'
var mult = 3
var str2 = ''
for(i = 0; i < mult; i++) {
str2 += str
}
console.log(str2)
var str = 'string'
var mult = 3;
var sol =""
while(mult--) {
sol +=str;
}
console.log(sol)
Using resusable function:
const concatStr= (str, mult)=>{
var sol =""
while(mult--) {
sol +=str;
}
console.log(sol)
}
concatStr("string",3)
Using the inbuilt Array.from method:
var str = "string"
var mult = 3
var sol = Array.from({length: mult}, ()=> str).join("")
console.log(sol)
function concatString(str, mult) {
var result = ''
for(i = 0; i < mult; i++) {
result = result.concat(str);
}
return result;
}
const value = concatString('string', 3);
console.log(value);
Also you can use array inbuilt methods,
const mult = 3, displayVal = 'str';
Array(mult).fill(displayVal).join('');
// the string object has a repeat method
console.log('string'.repeat(3));

Summing of Two Arrays in App Scripts (Google Sheets)

I'm working with a Spreadsheet where I need to get the values of 2 ranges (in arrays) and return the sum of those.
I found code and tried to plug it in, but it seems to be just concatenating the 2 arrays instead of actually summing them up.
The data I'm pulling is from my spreadsheet. The arrays are 5 Columns and 23 rows. The arrays are of the same size.
Here is my function that grabs the values of each arrays. It will then run it through the Arrays_sum function I found and return and update the table with the new totals.
function updateBowl(){
var row = mainSheet.getActiveCell().getRow();
var tagCol = mainSheet.getRange("HP52");
var rowNum = mainSheet.getRange("HO52");
tagCol.setValue("N4:N" + row);
rowNum.setValue(row);
var humpedData = mainSheet.getRange("HL54:HP77").getValues();
var processedTable = mainSheet.getRange("ID54:IH77");
var currentData = processedTable.getValues();
var newTotals = Arrays_sum(humpedData,currentData);
var setNewTotals = processedTable.setValues(newTotals);
Logger.log("New Totals: " + newTotals);
}
This is a function I found that supposedly sums up each array that's plugged into it, but it is not working for me.
function Arrays_sum(array1, array2)
{
var result = [];
var ctr = 0;
var x=0;
if (array1.length === 0)
return "array1 is empty";
if (array2.length === 0)
return "array2 is empty";
while (ctr < array1.length && ctr < array2.length)
{
result.push(array1[ctr] + array2[ctr]);
ctr++;
}
if (ctr === array1.length)
{
for (x = ctr; x < array2.length; x++) {
result.push(array2[x]);
}
}
else
{
for (x = ctr; x < array1.length; x++)
{
result.push(array1[x]);
}
}
return result;
}
Any help would be appreciated!
Edit 1: Pasted picture of the log.
Edit 2: In my log picture the first 1386 value is from the first cell in the FIRST array.
The second 1386 is the first value in SECOND array.
So it seems to concatenating the first row array with the second row array.
For my testing purposes the values are the same (because of lazy) but when I can figure out the array sum, the current values and incoming values will be different.
SOLVED
Coopers answer worked. I'm not sure exactly what I tweaked to get it to work but this is the final working script.
It gets 2 different arrays (of the same size) and sums the values in each cell, then pastes those values into the second array (the current totals).
function updateBowl(){
var row = mainSheet.getActiveCell().getRow();
var tagCol = mainSheet.getRange("HP52");
var rowNum = mainSheet.getRange("HO52");
tagCol.setValue("N4:N" + row);
rowNum.setValue(row);
var humpedData = mainSheet.getRange("HL54:HP77").getValues();
var processedTable = mainSheet.getRange("ID54:IH77");
var currentData = processedTable.getValues();
var newTotals = sumarrays(humpedData,currentData);
var setNewTotals = processedTable.setValues(newTotals);
Logger.log("New Totals: " + newTotals);
}
function sumarrays(arr1,arr2) {
var o=[];
var html='[';
arr1.forEach(function(r,i) {
o[i]=[];
if(i>0){html+=','};
html+='[';
r.forEach(function(c,j){
if(j>0){html+=','};
o[i][j]=arr1[i][j]+arr2[i][j];
html+=o[i][j];
});
html+=']';
});
html+=']';
return o;
SpreadsheetApp.getUi().showModelessDialog(HtmlService.createHtmlOutput(html), 'Output');
}
Try something like this:
function arraytest() {
const ss=SpreadsheetApp.getActive();
const sh=ss.getSheetByName('Sheet1');
const a1=sh.getRange(1,1,9,9).getValues();
const a2=sh.getRange(1,10,9,9).getValues();
sumarrays(a1,a2);
}
function sumarrays(arr1,arr2) {
var o=[];
var html='[';
arr1.forEach(function(r,i) {
o[i]=[];
if(i>0){html+=','};
html+='[';
r.forEach(function(c,j){
if(j>0){html+=','};
o[i][j]=arr1[i][j]+arr2[i][j];
html+=o[i][j];
});
html+=']';
});
html+=']';
return o;
SpreadsheetApp.getUi().showModelessDialog(HtmlService.createHtmlOutput(html), 'Output');
}
Data:
1,10,19,28,37,46,55,64,73,82,91,100,109,118,127,136,145,154,163,172,181
2,11,20,29,38,47,56,65,74,83,92,101,110,119,128,137,146,155,164,173,182
3,12,21,30,39,48,57,66,75,84,93,102,111,120,129,138,147,156,165,174,183
4,13,22,31,40,49,58,67,76,85,94,103,112,121,130,139,148,157,166,175,184
5,14,23,32,41,50,59,68,77,86,95,104,113,122,131,140,149,158,167,176,185
6,15,24,33,42,51,60,69,78,87,96,105,114,123,132,141,150,159,168,177,186
7,16,25,34,43,52,61,70,79,88,97,106,115,124,133,142,151,160,169,178,187
8,17,26,35,44,53,62,71,80,89,98,107,116,125,134,143,152,161,170,179,188
9,18,27,36,45,54,63,72,81,90,99,108,117,126,135,144,153,162,171,180,189
Output:
[[83,101,119,137,155,173,191,209,227],[85,103,121,139,157,175,193,211,229],[87,105,123,141,159,177,195,213,231],[89,107,125,143,161,179,197,215,233],[91,109,127,145,163,181,199,217,235],[93,111,129,147,165,183,201,219,237],[95,113,131,149,167,185,203,221,239],[97,115,133,151,169,187,205,223,241],[99,117,135,153,171,189,207,225,243]]
You can put constraints on it depending upon how the data is collected.
I hope this script will be an answer and a guide.
You can use this inside your spreadsheet as a normal function. Like this:
=arr_arr(A1:D5,"+",F6:K9)
The code:
/**
* Return the sum of total array one + array two
*
* #param {A1:D10} range - First range to sum.
* #param {"+ - / *"} operator - Operator to use.
* #param {E1:F10} range - Second range to sum.
* #return the sum of all the values
* #customfunction
*/
function arr_arr(range1,op,range2) {
const one = [].concat(...range1);
const two = [].concat(...range2);
const sumOne = one.reduce((a, b) => a + b, 0);
const sumTwo = two.reduce((a, b) => a + b, 0);
let sum = 0;
switch (op) {
case "+":
sum = sumOne + sumTwo;
break;
case "-":
sum = sumOne - sumTwo;
break;
case "*":
sum = sumOne * sumTwo;
break;
case "/":
sum = sumOne / sumTwo;
break;
}
return sum;
}

Backpropagation in an Tensorflow.js Neural Network

When I have been attempting to implement this function tf.train.stg(learningRate).minimize(loss)into my code in order to conduct back-propagation. I have been getting multiple errors such The f passed in variableGrads(f) must be a function. How would I implement the function above into the code bellow successfully? and Why does this error even occur?
Neural Network:
var X = tf.tensor([[1,2,3], [4,5,6], [7,8,9], [10,11,12]])
var Y = tf.tensor([[0,0,0],[0,0,0], [1,1,1]])
var m = X.shape[0]
var a0 = tf.zeros([1,3])
var y_hat = tf.zeros([1,3])
var parameters = {
"Wax": tf.randomUniform([1,3]),
"Waa": tf.randomUniform([3,3]),
"ba": tf.zeros([1,3]),
"Wya": tf.randomUniform([3,3]),
"by": tf.zeros([1,3])
}
function RNN_cell_Foward(xt, a_prev, parameters){
var Wax = parameters["Wax"]
var Waa = parameters["Waa"]
var ba = parameters["ba"]
var a_next = tf.sigmoid(tf.add(tf.add(tf.matMul(xt, Wax), tf.matMul(a_prev , Waa)),ba))
return a_next
}
function RNN_FowardProp(X, a0, parameters){
var T_x = X.shape[0]
var a_next = a0
var i = 1
var Wya = parameters["Wya"]
var by = parameters["by"]
var l = 1
for(; i <= T_x; i++){
var X_i = X.slice([i-1,0],[1,-1])
for(; l <= X.shape[1]; l++){
var xt = X_i.slice([0,l-1],[1,1])
var a_next = RNN_cell_Foward(xt, a_next, parameters)
}
var y_pred = tf.sigmoid((tf.add(tf.matMul(a_next, Wya), by)))
l = 1
if (i == 1){
var y_pred1 = y_pred
} else if (i == 2) {
var y_pred2 = y_pred
} else if (i == 3) {
var y_pred3 = y_pred
}
}
var y_predx = tf.concat([y_pred1, y_pred2, y_pred3])
return y_predx
}
const learningRate = 0.01;
var optimizer = tf.train.sgd(learningRate);
var model = RNN_FowardProp(X, a0, parameters)
var loss = tf.losses.meanSquaredError(Y, model)
for (let f = 0; f < 10; f++) {
optimizer.minimize(loss)
}
This is a neural network for sentiment classification which has a many to one structure.
The error says it all:
The f passed in variableGrads(f) must be a function
optimizer.minimize is expecting a function as parameter and not a tensor. Since the code is trying to minimize the meanSquaredError, the argument of minimize can be a function that computes the meanSquaredError between the predicted value and the expected one.
const loss = (pred, label) => pred.sub(label).square().mean();
for (let f = 0; f < 10; f++) {
optimizer.minimize(() => tf.losses.meanSquaredError(Y, model))
}
Does it solve the issue, not completely yet ? The error will change for something like:
variableGrads() expects at least one of the input variables to be trainable
What does it mean ? When the optimizer is used, it expects the function passed as argument to contains variables whose values will be updated to minimize the function output.
Here is the changes to be made:
var Y = tf.tensor([[0,0,0],[0,0,0], [1,1,1]]).variable() // a variable instead
// var loss = tf.losses.meanSquaredError(Y, model)
// computed below in the minimize function
const learningRate = 0.01;
var optimizer = tf.train.sgd(learningRate);
var model = RNN_FowardProp(X, a0, parameters);
const loss = (pred, label) => pred.sub(label).square().mean();
for (let f = 0; f < 10; f++) {
optimizer.minimize(() => tf.losses.meanSquaredError(Y, model))
}

How do I fix this code? It's use 3 seperate functions one to add to the array, one to sort and one to display. Javascript

I'm doing a question that asks: Read 10 numbers and print the biggest number from the list of reading numbers. Make use of Array and Functions.
One Function to read the integer numbers and another function to print the biggest number from the list.
I'm having trouble with getting the biggest number and returning it back to the code so that I can display it. I've messed around with it allot so it might not make as much sense right now (I'm sorry).
I've been stuck on it forever any help would be much appreciated :).
var numbers = [];
var BiggestNumber = 0;
BigestNumber = BiggestSort(numbers);
numbers = ReadNumbers();
Display(BiggestNumber)
function ReadNumbers() {
var ArgNumbers = [];
var ArgInput;
var ctr;
for (ctr = 0; ctr < 3; ctr++) {
ArgInput = parseFloat(prompt("Please enter a number: "));
ArgNumbers.push(ArgInput);
}
return ArgNumbers;
}
function BiggestSort(ArgNumber) {
var ArgNumber = [];
var ArgBiggest = 0;
var ctr;
for (ctr = 0; ctr < 3; ctr++)
if (ArgNumber[ctr] > ArgBiggest) {
ArgBiggest = ArgNumber[ctr];
}
return ArgBiggest;
}
function Display(ArgNumber) {
alert("The biggest number was: " + ArgNumber);
}
I've added a snippet at the end that demonstrates how I might do such a thing from scratch, but let's look at your code first:
From the top:
There's no need to declare numbers and BiggestNumber with initial values and then immediately reassign them. Declare them at assignment time:
// var numbers = [];
// var BiggestNumber = 0;
const BigestNumber = BiggestSort(numbers);
const numbers = ReadNumbers();
There's a typo in BigestNumber (missing second 'g'):
// const BigestNumber = BiggestSort(numbers);
const BiggestNumber = BiggestSort(numbers);
const numbers = ReadNumbers();
You're calling BiggestSort(numbers) before numbers has a meaningful value. Call ReadNumbers() first to initialize numbers, then pass it to BiggestSort:
// const BiggestNumber = BiggestSort(numbers);
// const numbers = ReadNumbers();
const numbers = ReadNumbers();
const BiggestNumber = BiggestSort(numbers);
Again, no need to declare ArgInput and ctr separately. It doesn't really hurt anything, but it's unnecessary:
function ReadNumbers() {
const ArgNumbers = [];
// var ArgInput;
// var ctr;
for (let ctr = 0; ctr < 3; ctr++) {
const ArgInput = parseFloat(prompt("Please enter a number: "));
ArgNumbers.push(ArgInput);
}
return ArgNumbers;
}
You're receiving an ArgNumber parameter, and then declaring another variable with the same name. Use the argument passed in.
Because the ArgNumber parameter is an array, you can use its length property in the loop condition instead of hard-coding 3.
You're missing curly braces around your loop body.
function BiggestSort(ArgNumber) {
// var ArgNumber = [];
let ArgBiggest = 0;
// var ctr;
// for (ctr = 0; ctr < 3; ctr++)
for (let ctr = 0; ctr < ArgNumber.length; ctr++) { // added curly brace
if (ArgNumber[ctr] > ArgBiggest) {
ArgBiggest = ArgNumber[ctr];
}
} // added closing brace
return ArgBiggest;
}
With the changes described above, it works:
const numbers = ReadNumbers();
const BiggestNumber = BiggestSort(numbers);
Display(BiggestNumber);
function ReadNumbers() {
const ArgNumbers = [];
for (let ctr = 0; ctr < 3; ctr++) {
const ArgInput = parseFloat(prompt("Please enter a number: "));
ArgNumbers.push(ArgInput);
}
return ArgNumbers;
}
function BiggestSort(ArgNumber) {
let ArgBiggest = 0;
for (let ctr = 0; ctr < ArgNumber.length; ctr++) {
if (ArgNumber[ctr] > ArgBiggest) {
ArgBiggest = ArgNumber[ctr];
}
}
return ArgBiggest;
}
function Display(ArgNumber) {
alert("The biggest number was: " + ArgNumber);
}
Consider this approach:
// A function to prompt for a series of numbers:
// The 'count' parameter is how many numbers to prompt for.
// The 'previous' parameter is an array of the numbers already entered, initally empty.
function readNumbers (count, previous = []) {
// if count is zero, we're done. return the already entered numbers.
if (count === 0) {
return previous;
}
// prompt for the next number
const number = parseFloat(prompt('Enter a number: '));
// push the new number onto the end of the list
previous.push(number);
// call readNumbers again, subtracting one from 'count'
// and return whatever it returns.
return readNumbers(count - 1, previous);
}
// invoke readNumbers to prompt the user.
const numbers = readNumbers(3);
// use Math.max to find the largest number
const largest = Math.max(...numbers);
// show the result
alert(`The biggest number was ${largest}`);
Correct typos like BigestNumber and BiggestNumber.
do ReadNumbers before BiggestSort method call.
remove\avoid reassigning to parameters\args you pass into method scopes, i.e. ArgNumber in the BiggestSort method.
var numbers = [];
numbers = ReadNumbers(3);
BiggestNumber = BiggestSort(numbers);
Display(BiggestNumber)
function ReadNumbers(numberToRead) {
var ArgNumbers = [];
var ArgInput;
for (var ctr = 0; ctr < numberToRead; ctr++) {
ArgInput = parseFloat(prompt("Please enter a number: "));
ArgNumbers.push(ArgInput);
}
return ArgNumbers;
}
function BiggestSort(ArgNumber) {
var ArgBiggest = 0;
for (var ctr = 0, max = ArgNumber.length; ctr < max; ctr++)
if (ArgNumber[ctr] > ArgBiggest) {
ArgBiggest = ArgNumber[ctr];
}
return ArgBiggest;
}
function Display(ArgNumber) {
alert("The biggest number was: " + ArgNumber);
}
I also passed in the number of loops (numberToRead) and ensure the loop in BiggestSort uses the length of the passed array (ArgNumber).

Need help looping though 3 loops to append data in Google Scripts

I am working with Col A, B & C. Col A contains A-E, Col B Contains 1, a, 3, b, 5 and Col C will be where I will store duplicated information (a and b would go into C1 & C2). Any help would be appreciated. In summary; compare A and B for similarity, output result into C
function appendString() {
var range = SpreadsheetApp.getActiveSheet().getRange("A1:A5");
var range2 = SpreadsheetApp.getActiveSheet().getRange("B1:B5");
var range3 = SpreadsheetApp.getActiveSheet().getRange("C1:C5")
var numRows = range.getNumRows();
var x = 0
// var numCols = range.getNumColumns();
j = 1 // row A
k = 2 // row B
m = 3 // row C
n = 1
// First loop though B
for (var i = 1; i <= numRows; i++) {
// set the current value...
var currentValue = range.getCell(i, j).getValue();
// In the log tell us the current value
Logger.log("Set A:" + currentValue);
// Loops though col B to compare to col A
for (var l = 1; l <= numRows; l++) {
// Sets the current value to compare value
var compareValue = range2.getCell(l, j).getValue();
Logger.log("Set B:" + compareValue)
// If the compareValue and the currentValue (match)
if (compareValue === currentValue) {
Logger.log("MATCHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH");
// We will write the result to col C down one row
for (n; n <= x; n++) {
// this makes it only run once'
range3.setValue(currentValue);
Logger.log("Appending.................");
x = n + 3
}
}
}
}
}
I think your problem statement boils down to this: Fill column C with a list of unique values that appear in both column A and B.
There is a built-in javascript Array method Array.indexOf() that makes it very easy to search for matching elements. As the problem is defined, we want to search in a column, so to use that method we need a column to be represented as an Array. The Range.getValues() method allows us to load a whole range of values at once, and delivers them as a two-dimensional array, with rows as the first dimension. We need columns there, and we can achieve that by a matrix transposition.
So here's what we end up with. There isn't a built-in transpose(), so I've included one. As we search for matches, results are stored in an Array C, using the built-in Array.push() method. Finally, array C is treated as a two-dimensional array, transposed, and written out to the sheet in column C.
function recordMatches() {
var range = SpreadsheetApp.getActiveSheet().getRange("A1:B5");
var data = range.getValues();
// For convenience, we'll transpose the data, so
// we can treat columns as javascript arrays.
var transposed = transpose(data);
var A = transposed[0],
B = transposed[1],
C = [];
// Go through A, looking for matches in B - if found, add match to C
for (var i=0; i < A.length; i++) {
if (B.indexOf(A[i]) !== -1) C.push(A[i]);
}
// If any matches were found, write the resulting array to column C
if (C.length > 0) {
var rangeC = SpreadsheetApp.getActiveSheet().getRange(1,3,C.length);
rangeC.setValues(transpose([C]));
}
}
function transpose(a) {
return Object.keys(a[0]).map(function (c) { return a.map(function (r) { return r[c]; }); });
}

Categories