How can I make this to a loop? - javascript

How can I make this to a loop? the array tabProsent contains 70 numbers.
var startVerdi=1000;
if(slider.value==tab[0]){
output2.innerHTML = startVerdi*tabProsent[0];
}
if(slider.value==tab[1]){
output2.innerHTML = startVerdi*tabProsent[0]*tabProsent[1];
}
if(slider.value==tab[2]){
output2.innerHTML = startVerdi*tabProsent[0]*tabProsent[1]*tabProsent[2];
}
if(slider.value==tab[3]){
output2.innerHTML = startVerdi*tabProsent[0]*tabProsent[1]*tabProsent[2]*tabProsent[3];
}

You can use the array methods indexOf(), slice(), and reduce():
var startVerdi=1000;
var index = tab.indexOf(slider.value);
if (index !== -1) {
output2.innerHTML = tabProsent.slice(0, index + 1).reduce(
(acc, cur) => acc * cur, startVerdi
);
}

You could do something like this -
var startVerdi=1000;
for(let i=0;i<70;i++){ // check for tab[0], tab[1] and so on...
if(slider.value == tab[i]){
let temp = startVerdi;
for(let j=0;j<=i;j++){
temp = temp * tabProsent[j] // multiply with tabProsent[0], tabProsent[1] and so on...
}
output2.innerHTML = temp;
}
}

Here is a simple and understandable method : you need two loops:
One to find the index of tab that corresponds to the slider value
Another (inner loop) to create the product of values of tabProsent that are smaller or equal to the index of tab:
const MAX_TAB_IDX = 69; // 0 to 69 gives 70 values
let startVerdi=1000;
for(let idx=0; idx<=MAX_TAB_IDX; idx++) { // First loop
if(slider.value == tab[idx]) { // We found it!! Lets calculate the product..
let product=1;
for(let subidx=0; subidx <= idx; subidx ++) // Second loop
product *= tabProsent[subidx];
output2.innerHTML = startVerdi * product;
break; // This is to stop the loop!
}
}
There are other more elegant ways (for example, using slice and map functions) - this is so you can understand how it works.

Based on the comments under the question and answer from Patrick Roberts, here is working example:
// Prepare data:
var startVerdi = 1000;
let tabProsent = [];
for (let i = 0; i < 70; i++) tabProsent.push(Math.random() * 0.13 + 1);
function sliderChanged(val) {
const index = val - 1950;
const total = tabProsent.slice(0, index + 1).reduce(
(acc, cur) => acc * cur, startVerdi
);
document.getElementById('result').innerHTML = total;
}
<input type="range" min="1950" max="2020" onchange="sliderChanged(this.value)" oninput="sliderChanged(this.value)" />
<label id="result">?</label>

Related

Return value from an array based on input that fits between two steps of another array

I start off with two arrays like this
const colors = ["#00876c", "#50a26f", "#88bb72", "#c1d379", "#fde987", "#fac067", "#f49654", "#e86b4e", "#d43d51"];
const steps = [13.5, 13.6875, 13.875, 14.0625, 14.25, 14.4375, 14.625, 14.8125, 15];
Both the colors array and steps array have the same length, so you can interpret it as each step associating with the color at the given index.
What I'm trying to do is, based on the value of an input, fit it between the steps and associate said input with its color.
For example:
returnColor(13.2) // returns #00876c
returnColor(20) // returns #d43d51
returnColor(13.7) // returns #50a26f
returnColor(14.5) // returns #fac067
Feel free to ask any question if I haven't explained quite well.
You can use the closest function from this answer to get the index which is most similar to the input provided.
const colors = ["#00876c", "#50a26f", "#88bb72", "#c1d379", "#fde987", "#fac067", "#f49654", "#e86b4e", "#d43d51"];
const steps = [13.5, 13.6875, 13.875, 14.0625, 14.25, 14.4375, 14.625, 14.8125, 15];
//get the index of the element which is closest to the step
function closest(num, arr) {
var curr = arr[0],
diff = Math.abs(num - curr),
index = 0;
for (var val = 0; val < arr.length; val++) {
let newdiff = Math.abs(num - arr[val]);
if (newdiff < diff) {
diff = newdiff;
curr = arr[val];
index = val;
}
}
return index;
}
function returnColor(step) {
const index = closest(step, steps);
return colors[index];
}
//Tests
console.log(returnColor(13.2)); // returns #00876c
console.log(returnColor(20)); // returns #d43d51
console.log(returnColor(13.7)); // returns #50a26f
console.log(returnColor(14.5)); // returns #fac067

How to increment set of 2 letters based on word occurrences in the range using GAS?

I got this one that looks hairy to me, but I'm confident you guys can crack it while having fun.
The problem:
Check of Company exists in the range
If not, get the latest ID prefix, which looks like AA, AB, etc
Generate a new prefix, which would be the following, according to item above: AC
If that company occurs more than once, then increment the ID number sufix XX001, XX002, etc.
This is what I've come up with so far:
function generateID() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const clientSheet = ss.getSheetByName('Clients');
const dataRng = clientSheet.getRange(8, 1, clientSheet.getLastRow(), clientSheet.getLastColumn());
const values = dataRng.getValues();
const companies = values.map(e => e[0]);//Gets the company for counting
for (let a = 0; a < values.length; a++) {
let company = values[a][0];
//Counts the number of occurrences of that company in the range
var companyOccurrences = companies.reduce(function (a, b) {
return a + (b == company ? 1 : 0);
}, 0);
if (companyOccurrences > 1) {
let clientIdPrefix = values[a][2].substring(0, 2);//Gets the first 2 letters of the existing company's ID
} else {
//Generate ID prefix, incrementing on the existing ID Prefixes ('AA', 'AB', 'AC'...);
let clientIdPrefix = incrementChar(values[a][2].substring(0,1));
Logger.log('Incremented Prefixes: ' + clientIdPrefix)
}
}
}
//Increment passed letter
var alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('')
function incrementChar(c) {
var index = alphabet.indexOf(c)
if (index == -1) return -1 // or whatever error value you want
return alphabet[index + 1 % alphabet.length]
}
...and this is borrowing from tckmn's answer, which deals with one letter only.
This is the expected result:
This is the link to the file, should anyone want to give it a shot.
Thank you!
In your situation, how about the following modification?
Modified script:
// Please run this function.
function generateID() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('Clients');
const dataRng = sheet.getRange(8, 1, sheet.getLastRow() - 7, 1);
const values = dataRng.getValues();
let temp = "";
let init = "";
let count = 0;
const res = values.map(([a], i) => {
count++;
if (temp != a) {
count = 1;
temp = a;
init = i == 0 ? "AA" : wrapper(init);
}
return [`${init}${count.toString().padStart(3, "0")}`];
});
console.log(res)
sheet.getRange(8, 4, res.length, 1).setValues(res);
}
//Increment
var alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('')
function incrementChar(c) {
var index = alphabet.indexOf(c)
if (index == -1) return -1 // or whatever error value you want
return alphabet[index + 1 % alphabet.length]
}
// I added this function.
function wrapper(str) {
const [a, b] = [...str];
const r1 = incrementChar(a);
const r2 = incrementChar(b);
return (r2 ? [a, r2] : (r1 ? [r1, "A"] : ["over"])).join("");
}
In this modification, I added a wrapper function. This wrapper function uses your showing script of incrementChar.
When this script is run to your sample Spreadsheet, console.log(res) shows [["AA001"],["AA002"],["AA003"],["AA004"],["AA005"],["AB001"],["AB002"],["AB003"],["AC001"]]. And this value is put to the column "D".
Note:
This modified sample is for your provided Spreadsheet. So please be careful this.
Reference:
map()

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;
}

javascript using reduce function

I have the below array
["0,5,p1", "24,29,p2", "78,83,p2", "78,83,p3", "162,167,p2" ]
i want the output as ["5,p1","10,p2","5,p3"] , so p1..3 are video files paying time with start and end time . 0,5 mean p1 profile played for 5 sec and so on.
I want to know what profile take what time in total using ECMA script map,reduce function. Here is what i tried but it doesnt work:
var ca = uniqueArray.reduce(function(pval, elem) {
var spl = elem.split(',');
var difference = Math.round(spl[1] - spl[0]);
return difference;
},elem.split(',')[3]);
I dont think it can be done in one pass, but I could be wrong. I'd go for a 2 step...
Reduce the array to get unique map of pX values
Map the result back to an array in the required format
var input = ["0,5,p1", "24,29,p2", "78,83,p2", "78,83,p3", "162,167,p2" ]
var step1 = input.reduce(function(p,c){
var parts = c.split(",");
if(!p[parts[2]])
p[parts[2]] = 0;
p[parts[2]] += parseInt(parts[1],10) - parseInt(parts[0],10);
return p;
},{});
var result = Object.keys(step1).map(function(e){
return step1[e] + "," + e;
});
console.log(result);
You could use es6 map:
arrayWithNumbers.map(a => {var spl = a.split(','); return (spl[1] - spl[0]) + "," + spl[2]})
For a single loop approach, you could use a hash table for same third parts, like 'p1'. If a hash is given, then update the value with the actual delta.
var array = ["0,5,p1", "24,29,p2", "78,83,p2", "78,83,p3", "162,167,p2"],
hash = Object.create(null),
result = array.reduce(function(r, a) {
var parts = a.split(','),
delta = parts[1] - parts[0],
key = parts[2];
if (!(key in hash)) {
hash[key] = r.push([delta, key].join()) - 1;
return r;
}
r[hash[key]] = [+r[hash[key]].split(',')[0] + delta, key].join();
return r;
}, []);
console.log(result);
I have updated the code. Please check now.
var ca = ["0,5,p1", "24,29,p2", "78,83,p2", "78,83,p3", "162,167,p2" ] .reduce(function(result, elem) {
var spl = elem.split(',');
var difference = Math.round(spl[1] - spl[0]);
var found = false
for (var i = 0 ; i < result.length; i++) {
if (result[i].split(',')[1] == spl[2]) {
result[i] = parseInt(result[i].split(',')[0]) + difference+","+spl[2];
found = true;
}
}
if (!found) result.push(difference+","+spl[2]);
return result;
},[]);
console.log("modified array",ca);

Array text to numbers, find matching values and sort

I have an array which looks like this:
["1,8", "4,6,8", "8,9", "6,9"]
1/ I would like to turn it in to this
[1,8,4,6,8,8,9,6,9]
2/ I would then like to find matching values, by looking for the most number:
[8]
This first has been solved with this:
var carArray = ["1,8", "4,6,8,7,7,7,7", "8,9", "6,9"];
//1) create single array
var arr = carArray.join().split(',');
//2) find most occurring
var counts = {}; //object to hold count for each occurence
var max = 0, maxOccurring;
arr.forEach(function(el){
var cnt = (counts[el] || 0); //previous count
counts[el] = ++cnt;
if(cnt > max && cnt > 1){ //only register if more than once (cnt>1)
max=cnt;
maxOccurring = el;
}
});
if(maxOccurring){
//there was an element more than once, maxOccuring contains that element
setResult('Most occuring: ' + maxOccurring + ' (' + max + ' times)');
}
else{
//3)/4) ???
setResult('sorting?');
}
//below is only for test display purposes
function setResult(res){
console.log(res);
}
3/ If the are no matching values like this
[1,8,4,6,5,7]
4/ Then I need to compare this array to another array, such as this
[6,7,4,1,2,8,9,5]
If the first number in <4> array above appears in <3> array, then get that number, ie in the above example I need to get 6. The <4> array will be static values and not change. The numbers is <3> will be dynamic.
EDIT Not the most elegant of answers, but I do have something working now. I didn't compare the original array directly with the second array, instead used simple if/else statements to do what I needed:
var carArray = ["1,5", "4", "8,2", "3,9,1,1,1"];
//1) create single array
var arr = carArray.join().split(',');
//2) find most occurring
var counts = {}; //object to hold count for each occurence
var max = 0, maxOccurring;
arr.forEach(function(el){
var cnt = (counts[el] || 0); //previous count
counts[el] = ++cnt;
if(cnt > max && cnt > 1){ //only register if more than once (cnt>1)
max=cnt;
maxOccurring = el;
}
});
if(maxOccurring){
//there was an element more than once, maxOccuring contains that element
console.log('Most occuring: ' + maxOccurring + ' (' + max + ' times)');
console.log(maxOccurring);
}
else {
// If not occuring, match from a list
if(jQuery.inArray("6", arr) !== -1) { console.log('6'); }
else if(jQuery.inArray("9", arr) !== -1) { console.log('9'); }
else if(jQuery.inArray("7", arr) !== -1) { console.log('7'); }
else if(jQuery.inArray("5", arr) !== -1) { console.log('5'); }
else if(jQuery.inArray("4", arr) !== -1) { console.log('4'); }
else if(jQuery.inArray("1", arr) !== -1) { console.log('1'); }
else { console.log('not found'); }
}
Example Fiddle
Step 1 is fairly easy by using javascript's join and split methods respectively:
var arr = carArray .join().split(',');
For step 2, several methods can be used, the most common one using an object and using the elements themselves as properties. Since you only need to get the most occurring value if there is a reoccurring value, it can be used in the same loop:
var counts = {}; //object to hold count for each occurence
var max = 0, maxOccurring;
arr.forEach(function(el){
var cnt = (counts[el] || 0); //previous count
counts[el] = ++cnt;
if(cnt > max && cnt > 1){ //only register if more than once (cnt>1)
max=cnt;
maxOccurring = el;
}
});
After the above, the variable maxOccurring will contain the reoccurring value (if any) and max will contain the times it occured
For step 4 the easiest way is to loop through the compare array and get the element that occurs in the input array:
var cmpArr = ['6','7','4','1','2','8','9','5'];
//find the first occurrence inside the cmpArr
res = function(){ for(var i= 0 ; i < cmpArr.length; i++){ if(arr.indexOf(cmpArr[i]) !== -1)return cmpArr[i];}}();
The above uses an in place function which is called immediately to be able to use return. You could also just use a loop and assign res when found, then break from the loop.
Last update, an alternate fiddle where the above is converted to a single function: http://jsfiddle.net/v9hhsdny/5/
Well first of all the following code results in four matching answers since the jQuery selectors are the same.
var questionAnswer1 = $(this).find('input[name=questionText]').val();
var questionAnswer2 = $(this).find('input[name=questionText]').val();
var questionAnswer3 = $(this).find('input[name=questionText]').val();
var questionAnswer4 = $(this).find('input[name=questionText]').val();
var carArray = [questionAnswer1, questionAnswer2, questionAnswer3, questionAnswer4];
You could use the eq(index) method of jQuery to select the appropriate element. However having 4 inputs with the same name is a bad practice.
Well lets say that the carArray has 4 different values which all consist out of comma separated numbers. You could then do the following:
var newArr = [];
carArray.forEach(function(e) {
e.split(",").forEach(function(n) {
newArr.push(n);
});
});
Well then we got to find the most occurring number. JavaScript doesn't have any functions for that so we will have to find an algorithm for that. I found the following algorithm on this stackoverflow page
var count = function(ary, classifier) {
return ary.reduce(function(counter, item) {
var p = (classifier || String)(item);
counter[p] = counter.hasOwnProperty(p) ? counter[p] + 1 : 1;
return counter;
}, {})
}
var occurances = count(newArr);
It isn't clear to me what you're trying to do in step 3 and 4, so can't answer those at the moment.
var ary = ["1,8", "4,6,8", "8,9", "6,9"];
var splitted = ary.reduce(function(acc, item) {
return acc.concat(item.split(','));
}, []);
var occurences = splitted.reduce(function(acc, item) {
if (!acc.hasOwnProperty(item)) acc[item] = 0;
acc[item] += 1;
return acc;
},{}),
biggest = Object.keys(occurences).reduce(function (acc, key) {
if (occurences[key] > acc.occurences) {
acc.name = key;
acc.occurences = occurences[key];
}
return acc;
},{'name':'none','occurences':0}).name;
var vals=["1,8", "4,6,8", "8,9", "6,9"];
// 1) turn into number array
var arrNew=[];
for(var i=0; i<vals.length; i++)
{
arrLine=vals[i].split(",");
for (var j=0;j<arrLine.length;j++) { arrNew.push (parseInt(arrLine[j])) }
}
//result:
alert(arrNew.join(";");
// 2) find most common
var found=[];
for(var i=0; i<arrNew.length; i++) {
// make an array of the number of occurrances of each value
if (found["num"+newArray[i]]) {
found["num"+newArray[i]] ++ ;
} else {
found["num"+newArray[i]]=1;
}
}
var mostCommon={count:0,val:"ROGUE"};
for (x in found) {
if (found[x] > mostCommon.count) {
mostCommon.count=found[x].count;
mostCommon.val=x;
}
}
// result :
alert(mostCommon.val);
//3) not quite sure what you meant there
// 4) unique values:
// at this point the 'found' list contains unique vals
var arrUnique=[];
for (x in found) {
arrUnique.push[x];
}
// result :
alert(arrUnique.join(";"))
//sort:
arrUnique.sort(function(a, b){return a-b});
(This won't work in most browsers) but on a side note, when ES6 becomes widely supported, your solution could look like this:
var arr1 = ["1,8", "4,6,8", "8,9", "6,9"];
var arr2 = arr1.join().split(',');
var s = Array.from(new Set(arr2)); //Array populated by unique values, ["1", "8", "4", "6", "9"]
Thought you might like to see a glimpse of the future!
1.
var orgArray = ['1,8', '4,6,8', '8,9', '6,9'];
var newArray = [];
for (var i in orgArray) {
var tmpArray = orgArray[i].split(',');
for (var j in tmpArray) {
newArray.push(Number(tmpArray[j]));
}
}
2.
var counts = {};
var most = null;
for (var i in newArray) {
var num = newArray[i];
if (typeof counts[num] === 'undefined') {
counts[num] = 1;
} else {
++(counts[num]);
}
if (most == null || counts[num] > counts[most]) {
most = num;
} else if (most != null && counts[num] === counts[most]) {
most = null;
}
}
I don't understand the question 3 and 4 (what "unique order" means) so I can't answer those questions.

Categories