Updating array values - javascript

I'm putting together a quiz with A/B questions. Every answer has 5 parameters that have to be updated as the user advances through the quiz to show a final results page.
It's very simple but I can't figure out why the parameters aren't updating. This is my first Javascrips project, can somebody point me in the right direction? Thank you!
//The five parameters to be updated
let totalOrg = 2;
let totalDel = 2;
let totalMod = 0;
let totalLux = 2;
let totalSer = 2;
// Array with values to modify the parameters for A or B answers
var valueDataA = [
[1,2,5,1,3],
[6,5,1,2,8]
];
var valueDataB = [
[-6,-3,-7,-3,-2],
[-1,-7,-5,-2,-3]
];
//Function to add the values to the parameters
function chooseOptionA() {
totalOrg = totalOrg + valueDataA[currentQuestion][0];
totalDel = totalDel + valueDataA[currentQuestion][1];
totalMod = totalMod + valueDataA[currentQuestion][2];
totalLux = totalLux + valueDataA[currentQuestion][3];
totalSer = totalSer + valueDataA[currentQuestion][4];
console.log(totalParameters);
};
function chooseOptionB() {
totalOrg = totalOrg + valueDataB[currentQuestion][0];
totalDel = totalDel + valueDataB[currentQuestion][1];
totalMod = totalMod + valueDataB[currentQuestion][2];
totalLux = totalLux + valueDataB[currentQuestion][3];
totalSer = totalSer + valueDataB[currentQuestion][4];
console.log(totalParameters);
};
let totalParameters = [totalOrg, totalDel, totalMod, totalLux, totalSer];

When you place totalOrg in the array totalParameters, you are not placing a pointer to the first variable, but the value, i.e. 2. So the final line of code is no different from:
let totalParameters = [2, 2, 0, 2, 2];
This will clarify why that array is not getting any changes when the functions are called. There are several ways to do this. I will propose one, where the first "parameter" values are stored in a single object, whose property names correspond to your current variable names. You must then adapt the rest of your code to reference those properties:
let totalParameters = {
totalOrg: 2,
totalDel: 2,
totalMod: 0,
totalLux: 2,
totalSer: 2
};
var valueDataA = [
[1,2,5,1,3],
[6,5,1,2,8]
];
var valueDataB = [
[-6,-3,-7,-3,-2],
[-1,-7,-5,-2,-3]
];
function chooseOptionA() {
totalParameters.totalOrg += valueDataA[currentQuestion][0];
totalParameters.totalDel += valueDataA[currentQuestion][1];
totalParameters.totalMod += valueDataA[currentQuestion][2];
totalParameters.totalLux += valueDataA[currentQuestion][3];
totalParameters.totalSer += valueDataA[currentQuestion][4];
console.log(totalParameters);
};
function chooseOptionB() {
totalParameters.totalOrg += valueDataB[currentQuestion][0];
totalParameters.totalDel += valueDataB[currentQuestion][1];
totalParameters.totalMod += valueDataB[currentQuestion][2];
totalParameters.totalLux += valueDataB[currentQuestion][3];
totalParameters.totalSer += valueDataB[currentQuestion][4];
console.log(totalParameters);
};

Let me pitch you a different approach
//The five parameters to be updated
let totalOrg = 2;
let totalDel = 2;
let totalMod = 0;
let totalLux = 2;
let totalSer = 2;
// Array with values to modify the parameters for A or B answers
var valueDataA = [
[1,2,5,1,3],
[6,5,1,2,8]
];
var valueDataB = [
[-6,-3,-7,-3,-2],
[-1,-7,-5,-2,-3]
];
/**
* updateParameters
*
* Function to update the values of the parameters
*
* #param {Array<Number>} parameters
* #param {Array<Number>} parameterUpdates
* #returns {Array<Number>}
*/
function updateParameters(parameters, parameterUpdates) {
for (let i = 0; i < parameters.length; i++) {
parameters[i] += parameterUpdates[i];
}
return parameters;
}
let totalParameters = [totalOrg, totalDel, totalMod, totalLux, totalSer];
for (let currentQuestionIndex = 0; currentQuestionIndex < 2 /** questions.length */; currentQuestionIndex++) {
let option = 'A'; /** actually getUserChoice(); */
if (option == 'A') {
totalParameters = updateParameters(totalParameters, valueDataA[currentQuestionIndex])
} else if(option == 'B') {
totalParameters = updateParameters(totalParameters, valueDataB[currentQuestionIndex])
}
console.log(totalParameters);
// you can use destructuring assignment to get individual parameters written
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
[totalOrg, totalDel, totalMod, totalLux, totalSer] = totalParameters;
}

Related

Is there a way to add values to some random cells from a range?

I have the following code:
function test1() {
var app = SpreadsheetApp;
var activesheet = app.getActiveSpreadsheet().getActiveSheet();
for (var j = 2; j<= 3; j++) {
activesheet.getRange(j,2).setValue("C");
}
}
This code will add the character "C" to the cell B2 and B3 which is great.
I am looking to get my code to add two "C" characters to 2 random cells from the first 30 cells of the B column.
Any help is much appreciated. Thank you.
This code may help you
function test1() {
var app = SpreadsheetApp;
var activesheet = app.getActiveSpreadsheet().getActiveSheet();
let randomCellIndex;
let usedCell = [];
for (var i = 0; i < 2; i++) {
// make sure not to use same index twice
do
randomCellIndex = Math.floor(Math.random() * 30) + 1;
while (usedCell.indexOf(randomCellIndex) !== -1);
usedCell.push(randomCellIndex);
activesheet.getRange(randomCellIndex,2).setValue("CC");
}
}
I assume that you don't want duplicate values so i would grab two values from shuffled array. To avoid going into the rabbit hole with shuffling array exsample uses underscore
_.shuffle([...Array(30)].map((value, index) => index+1))
Adds character string to range n times making a unique selection each time.
function addCharsRandom(chr = "AB", a1rg = "", n = 3) {
const ss = SpreadsheetApp.getActive();
const sh = ss.getActiveSheet();
const rg = (a1rg.length < 2) ? sh.getActiveRange() : sh.getRange(a1rg);
if (rg.getDisplayValues().flat().length >= n) {
rg.setBackground("yellow")
const w = rg.getWidth();
const h = rg.getHeight();
const r = rg.getRow();
const c = rg.getColumn();
let rA = [];
let cA = [];
[...Array.from(new Array(n).keys())].forEach(i => {
let row, col;
do {
row = r + Math.floor(Math.random() * h);
col = c + Math.floor(Math.random() * w);
} while (rA.indexOf(row)>-1 && cA.indexOf(col)>-1);
rA.push(row);
cA.push(col);
sh.getRange(row, col).setValue(sh.getRange(row, col).getDisplayValue() + chr).setBackground("white");
});
} else {
SpreadsheetApp.getUi().alert("Range is to small for number of unique selections");
}
}
if a1rg equals "" then it will select the active range.
Demo:

Finding values between two values over a specific amount of time

let's say I have two values: 600 & 470
What I'm trying to do is specify a set of time, let's say 0 and 100 (4 seconds if 25fps) and then get the 'tween' values for each 'frame'.
var base = 600;
var target = 470;
var start = 0;
var end = 100;
var values = [];
for (var i = start; i < end; i++) {
// not sure where to begin with the math here
// so i'll just asssign it to i, but obviously it's wrong
var value = i;
values.push(value);
}
// Once complete, id expect:
// values[0] === 600;
// values[99] === 470;
How can I achieve this?
Calculate the increment (between each item in the array), and then you can create the array all at once by mapping each i to base + increment * i:
const base = 600;
const target = 470;
const start = 0;
const end = 100;
const increment = (target - base) / (end - start - 1);
const values = Array.from(
{ length: end - start },
(_, i) => base + increment * i
);
console.log(values[0]);
console.log(values[99]);
console.log(values);
I made an easy solution to this question.
Two variable added:
difference
rate
The base value minus rated differences to get step values.
var base = 600;
var target = 470;
var start = 0;
var end = 100;
var values = [];
var difference = base-target;
for (var i = start; i < end; i++) {
var rate = (i/(end-1));
var value = base - (difference*rate);
values.push(value);
}
// Once complete, id expect:
// values[0] === 600;
// values[99] === 470;
console.log(values);

create a random integer unique in a given array

<div id='passarr'>1572 4528 3564 8921 4521</div>
I need to create a new random integer (4 digits), unique regarding the above content.
js
var content = $('#passarr').text();
var passarr = content.split(' ');
var pass = Math.floor(Math.random() * 9000) + 1000;
var i = 0;
while (i == 0) {
if (jQuery.inArray(pass, passarr) > -1) {
var pass = Math.floor(Math.random() * 9000) + 1000;
i = 1;
}
}
seems it works, but not sure this is the right and shortest way.
any suggestion?
Your code is the way to go. However, you can eliminate a few smaller mistakes ( an unneccessary i and non working code in < 0.00001%) :
var content = $('#passarr').text();
var passarr = content.split(' ');
do {
var pass = Math.floor(Math.random() * 9000) + 1000;
} while (jQuery.inArray(pass, passarr) > -1);
console.log(pass);

How to generate 3 names without the same name repeated [duplicate]

This question already has an answer here:
Math random to find Names in an Array while not duplicating
(1 answer)
Closed 1 year ago.
window.onload = start;
function start () {
var name = ["Hans","Ole","Nils","Olav","Per","Knut","Kari","Line","Pia"]
var random = Math.floor(Math.random()*8)
var random2 = Math.floor(Math.random()*8)
var random3 = Math.floor(Math.random()*8)
var name2 = []
name2.push(name[random])
name2.push(name[random2])
name2.push(name[random3])
for(i=0; i<3; i++) {
document.getElementById("par").innerHTML += name2[i] + "<br/>" ;
}
}
So far with this code i can generate 3 random names from the name array. But i want the 3 names not to be repeated, and I don't know how to make that happen.
Perhaps this could help. I randomized the order of the array and then just pick the first three elements. This allows for zero repeats of names and generating a new answer each time the function is ran. Not sure what your HTML looks like so I just added the id "demo".
var players = ["Hans","Ole","Nils","Olav","Per","Knut","Kari","Line","Pia"];
function tournament() {
var names = [];
players.sort(function(a,b){return 0.5 - Math.random()});
for (i=0; i<3; i++){
names.push(players[i]);
}
document.getElementById("demo").innerHTML = names;
}
I created a solution that uses recursion.
The function randomNames gets repeated three times. Each time it gets called count gets increased and names is an array without the names that are already taken. It returns an array that holds the three random names.
function start () {
var name = ["Hans","Ole","Nils","Olav","Per","Knut","Kari","Line","Pia"]
function randomNames(count, names) {
if(count >= 3) return [];
var random = Math.floor(Math.random()*(names.length-1));
// remove current name
var name = names.splice(random, 1);
return randomNames(++count, names).concat(name);
}
var random = randomNames(0, name);
}
You could use a hash table for the chosen items and check against until all wanted items are found.
window.onload = start;
function start() {
var name = ["Hans", "Ole", "Nils", "Olav", "Per", "Knut", "Kari", "Line", "Pia"],
hash = {},
random;
while (Object.keys(hash).length < 3) {
do {
random = Math.floor(Math.random() * name.length);
} while (hash[random])
hash[random] = true;
document.getElementById("par").innerHTML += name[random] + "<br/>";
}
}
<div id="par"></div>
ES6 with Set
window.onload = start;
function start() {
var name = ["Hans", "Ole", "Nils", "Olav", "Per", "Knut", "Kari", "Line", "Pia"],
hash = new Set,
random;
while (hash.size < 3) {
do {
random = Math.floor(Math.random() * name.length);
} while (hash.has(random))
hash.add(random);
document.getElementById("par").innerHTML += name[random] + "<br/>";
}
}
<div id="par"></div>

Javascript: Random number out of 5, no repeat until all have been used

I am using the below code to assign a random class (out of five) to each individual image on my page.
$(this).addClass('color-' + (Math.floor(Math.random() * 5) + 1));
It's working great but I want to make it so that there are never two of the same class in a row.
Even better would be if there were never two of the same in a row, and it also did not use any class more than once until all 5 had been used... As in, remove each used class from the array until all of them have been used, then start again, not allowing the last of the previous 5 and the first of the next 5 to be the same color.
Hope that makes sense, and thanks in advance for any help.
You need to create an array of the possible values and each time you retrieve a random index from the array to use one of the values, you remove it from the array.
Here's a general purpose random function that will not repeat until all values have been used. You can call this and then just add this index onto the end of your class name.
var uniqueRandoms = [];
var numRandoms = 5;
function makeUniqueRandom() {
// refill the array if needed
if (!uniqueRandoms.length) {
for (var i = 0; i < numRandoms; i++) {
uniqueRandoms.push(i);
}
}
var index = Math.floor(Math.random() * uniqueRandoms.length);
var val = uniqueRandoms[index];
// now remove that value from the array
uniqueRandoms.splice(index, 1);
return val;
}
Working demo: http://jsfiddle.net/jfriend00/H9bLH/
So, your code would just be this:
$(this).addClass('color-' + (makeUniqueRandom() + 1));
Here's an object oriented form that will allow more than one of these to be used in different places in your app:
// if only one argument is passed, it will assume that is the high
// limit and the low limit will be set to zero
// so you can use either r = new randomeGenerator(9);
// or r = new randomGenerator(0, 9);
function randomGenerator(low, high) {
if (arguments.length < 2) {
high = low;
low = 0;
}
this.low = low;
this.high = high;
this.reset();
}
randomGenerator.prototype = {
reset: function() {
this.remaining = [];
for (var i = this.low; i <= this.high; i++) {
this.remaining.push(i);
}
},
get: function() {
if (!this.remaining.length) {
this.reset();
}
var index = Math.floor(Math.random() * this.remaining.length);
var val = this.remaining[index];
this.remaining.splice(index, 1);
return val;
}
}
Sample Usage:
var r = new randomGenerator(1, 9);
var rand1 = r.get();
var rand2 = r.get();
Working demo: http://jsfiddle.net/jfriend00/q36Lk4hk/
You can do something like this using an array and the splice method:
var classes = ["color-1", "color-2", "color-3", "color-4", "color-5"];
for(i = 0;i < 5; i++){
var randomPosition = Math.floor(Math.random() * classes.length);
var selected = classes.splice(randomPosition,1);
console.log(selected);
alert(selected);
}
var used = [];
var range = [0, 5];
var generateColors = (function() {
var current;
for ( var i = range[0]; i < range[5]; i++ ) {
while ( used.indexOf(current = (Math.floor(Math.random() * 5) + 1)) != -1 ) ;
used.push(current);
$(" SELECTOR ").addClass('color-' + current);
}
});
Just to explain my comment to jfriend00's excellent answer, you can have a function that returns the members of a set in random order until all have been returned, then starts again, e.g.:
function RandomList(list) {
var original = list;
this.getOriginal = function() {
return original;
}
}
RandomList.prototype.getRandom = function() {
if (!(this.remainder && this.remainder.length)) {
this.remainder = this.getOriginal().slice();
}
return this.remainder.splice(Math.random() * this.remainder.length | 0,1);
}
var list = new RandomList([1,2,3]);
list.getRandom(); // returns a random member of list without repeating until all
// members have been returned.
If the list can be hard coded, you can keep the original in a closure, e.g.
var randomItem = (function() {
var original = [1,2,3];
var remainder;
return function() {
if (!(remainder && remainder.length)) {
remainder = original.slice();
}
return remainder.splice(Math.random() * remainder.length | 0, 1);
};
}());

Categories

Resources