Related
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;
}
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);
I have seen this question answered here, but I have an additional question that is related.
Im trying to achieve:
the same thing, but, with the output being a selection of more than 1 number, the above works fine if you only want a single value returned.
How can I return (x) amount of outputs #7 in this case into a new var or array ...? Some guidance on best practice will also be appreciated ;)
Thanks a bunch....
Just for fun,
Objective:
Create a teeny weenie web App that returns 7 variable numbers in a range [ 1 - 49 ] into an array.
`
Think return a list of Lotto Numbers
Create new array from selection using _underscore.js [Sample function]
**** I know this is easier, but im trying to get an understanding
of using Vanilla JS to accomplish this
_.sample([1, 2, 3, 4, 5, 6], 3); => [1, 6, 2]
var getLoot = Array.from(Array(50).keys()) // Create array of 49 numbers.
console.info(getLoot);
var pick = getLoot[Math.floor(Math.random() * getLoot.length)];
pick;
// pick returns a single which is fine if you want a single but, ..
// I want something like this :
var pick = function() {
// code that will return 7 numbers from the array into a new Array
// will randomize every time pick is called...
}
If you want to return more than just 1 value you can store your results into a data structure like an array. Here is a solution to the problem
assuming you can pass in your array of 50 numbers into the pick() funciton.:
var getRandomArbitrary = function(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
var pick = function(fiftyNumberArray, numberOfValuesWanted) {
var randomNums = [];
for(var i = 0; i < numberOfValuesWanted; i++) {
randomNums.push(
fiftyNumberArray[getRandomArbitrary(0, 50)]
);
}
return randomNums;
};
var fiftyNumbers = [] // <- set your array of fifty numbers
pick(fiftyNumbers, 7);
Javascript's Math.random() will return a value in between 0 and 1 (exclusive). So to get an index scaled up to the correct value to look into your array, you would want to multiply that by the formula (max - min) + min
You can use Array.prototype.splice(), Math.floor(), Math.random(), for loop to remove elements from input array, return an array containing pseudo randomly picked index from input array without duplicate indexes being selected.
function rand(n) {
var res = []; var a = Array.from(Array(n).keys());
for (;a.length;res.push(a.splice(Math.floor(Math.random()*a.length),1)[0]));
return res
}
console.log(rand(50));
One good way of doing this job is shuffling the array and picking the first n values. Such as;
function shuffle(a){
var i = a.length,
j,
tmp;
while (i > 1) {
j = Math.floor(Math.random()*i--);
tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
return a;
};
var arr = Array(50).fill().map((_,i) => i+1); //[1,2,3...49,50]
randoms = shuffle(arr).slice(0,7) // to get 7 random numbers from arrary arr
console.log(randoms)
This is probably what you want.
$(function()
{
var lol = [1,4,5,6,7,8,9];
function getPart(array,number)
{
var part = [],
index;
while(true)
{
if(part.length == number)
{
break;
}
index = $.random(0,part.length);
part.push(lol.splice(index,1));
}
return part;
}
});
$.random = function(min,max,filter)
{
var i,
n = Math.floor(Math.random()*(max-min+1)+min);
if(filter != undefined && filter.constructor == Array)
{
for(i=filter.length-1;i>-1;i--)
{
if(n == filter[i])
{
n = Math.floor(Math.random()*(max-min+1)+min)
i = filter.length;
}
}
}
return n;
}
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.
There is probably a simple solution to this, but for some reason I can't seem to find it on the site, or elsewhere on the net. Just trying to produce a sentence of RANDOM LENGTH from an array. Here is an example:
var words = ["yes", "ok", "java", "pull my hair out", "sleep"];
Here is the code that I'm currently using to randomize the contents of the array, but it always produces a sentence where every string is used once. I want varying sentence lengths.
function fisherYates(words) {
var i = words.length, j, tempi, tempj;
if ( i == 0 ) return false;
while ( --i ) {
j = Math.floor( Math.random() * ( i + 1 ) );
tempi = words[i];
tempj = words[j];
words[i] = tempj;
words[j] = tempi;
}
return words;
}
Suggestions?
I would suggest you select a random number m from 1 to n inclusive (where n is the maximum length of the sentence you want). Then you randomly select m items from the array and put them into a new array:
var words = ["yes", "ok", "java", "pull my hair out", "sleep"];
alert(randomize(words, 10).join(" ") + ".");
function randomize(array, maximum) { // array, n
var length = Math.ceil(maximum * Math.random()); // m
var result = new Array(length);
var count = array.length;
var index = 0;
while (index < length) {
result[index++] = array[Math.floor(count * Math.random())];
}
return result;
}
Hope that helps.
Perhaps not.
If you don't want repeated strings, copy the array and splice random members from it to form the new collection. Just splice off a random number of strings from random positions.
function randWords(arr) {
// Copy original array
arr = arr.slice();
// Random number of words to get
var len = (Math.random() * arr.length + 1)|0;
var result = [];
// Randomly fill result from arr, don't repeat members
while (len--) {
result.push(arr.splice(Math.random()*arr.length|0, 1));
}
return result;
}
console.log( randWords(["yes", "ok", "java", "pull my hair out", "sleep"]).join(' ') );