I want to sum a list of numbers stored in a JavaScript object. The object is created and updated using this code:
var myscore = $('input[name="Points1"]').val();
scorelist = JSON.parse(localStorage.getItem(playerName + 'scorelist') || '[]');
scorelist.push(myscore);
localStorage.setItem(playerName + 'scorelist', JSON.stringify(scorelist));
$('div.scorecolumn', column).html("Score: <br>" + scorelist.join('<br>') + "<br>");
Basically I take whatever is in the column at the time, parse it, add myscore, stringify it, join each element with a <br> and write the list to the scorecolumn. The list of numbers is saved as an object. My goal is to sum up all the numbers in the object at any given time.
This script is inside of a function that passes in a bunch of parameters which is why some variables look undefined here.
Any help would be greatly appreciated! Thanks
UPDATE:
var nicTotalScore = nicScoreList.reduce(function(score, total) {
return total + score;
}, 0);
console.log(nicTotalScore); //12120
console.log(nicScoreList); //["12", "12"]
UPDATE:
If the score field is left blank when submitted, an empty string " " instead of a score. this is registering as a 0 when the reduce method goes through the array. This doesnt affect the total, but say, for example, i wanted to then find the average score, it throws it off. any ideas there? thanks
If you push() to scorelist, I'd be tempted to say it's likely an Array.
You could use reduce().
var total = scorelist.reduce(function(total, score) {
return total + +score;
}, 0);
Related
I want to get the sum of schema, using reduce. what the below codes do is not adding the item together but putting them next to each other. For example 20 + 30 should equal to 50 but it gives me 02030.
any problem with these codes?
Tracker.findById(req.params.id).populate("variations").exec(function(err, foundTracker){
if(err){
console.log(err);
}else{
const varSum = foundTracker.variations.reduce(function(sum, variation){
return sum + variation.varAmount;
}, 0);
foundTracker.varsum = varSum;
foundTracker.save(function(err, savedTracker){
Tracker and Variation are schema models
Currently you are just concatenating strings that's why you are not getting correct sum. Use parseInt() and you will get correct result.
Change this:
sum + variation.varAmount
to
parseInt(sum) + parseInt(variation.varAmount);
Try as I might I CANNOT decipher the problem that I'm having writing new rows to a sheet. I've done this several times and I've debugged this thoroughly using Logger.log, but I just can't solve it. Here's a summary of what I'm doing, a code snippet, and a log:
What I'm doing:
Adding rows to a sheet (below existing rows)
73 new rows are stored stored in array: Grade Rows
When attempt to write the new rows to the sheet, get this error:
Incorrect range width, was 1 should be 26
Here’s the code including some Logger.logs:
var BeginningRow = LastSGRowSheet + 1;
var EndingRow = BeginningRow + SGPushKtr -1;
Logger.log("BeginningRow =>" + BeginningRow + "<=, SGPushKtr =>" + SGPushKtr + "<=, Ending Row =>" + EndingRow + "<=");
var GradesRangeString = 'A' + BeginningRow + ':' + LastStudentGradesColumnLetter + EndingRow;
Logger.log("GradesRangeString =>" + GradesRangeString + "<=");
StudentGradeSheet.getRange(GradesRangeString).setValues(GradeRows);
The error occurs in that last line of code.
Here’s the log:
17-12-31 11:51:15:763 EST] BeginningRow =>364<=, SGPushKtr =>73<=, Ending Row =>436<=
[17-12-31 11:51:15:764 EST] GradesRangeString =>A364:Z436<=
Let's say that your data array is dA then the number of rows in that array is dA.length and assuming its a rectangular array then the number of columns is vA[0].length. So your output command has to be some thing like this.
sheet.getRange(firstRow,firstColumn,dA.length,dA[0].length).setValues(dA);
If you'd like to learn a little more about this problem check this out.
You could also append each row to the current sheet one row at a time in loop.
It's hard to know why GradeRows doesn't match your range without seeing all of your code.
Using Cooper's getRange arguments will likely reveal your problem, and will prevent you from having to update your row and column variables when you make changes to your code. Another issue that gets me sometimes is the fact that the setValues array needs to be exactly the same dimensions as the range. If one row has a different length, it will fail. If the logic I use to create row arrays can result in different lengths, I use the function below to make sure my arrays are symmetric before writing them to a sheet. It is also helpful for debugging.
/**
* Takes a 2D array with element arrays with differing lengths
* and adds empty string elements as necessary to return
* a 2D array with all element arrays of equal length.
* #param {array} ar
* #return {array}
*/
function symmetric2DArray(ar){
var maxLength;
var symetric = true;
if (!Array.isArray(ar)) return [['not an array']];
ar.forEach( function(row){
if (!Array.isArray(row)) return [['not a 2D array']];
if (maxLength && maxLength !== row.length) {
symetric = false;
maxLength = (maxLength > row.length) ? maxLength : row.length;
} else { maxLength = row.length }
});
if (!symetric) {
ar.map(function(row){
while (row.length < maxLength){
row.push('');
}
return row;
});
}
return ar
}
How about using appendRow()? That way you don't need to do lots of calculations about the range. You can loop through your data and add it row by row. Something like this:
myDataArr = [[1,2],[3,4],[5,6]]
myDataArr.forEach(function(arrayItem){
sheet.appendRow([arrayItem[0],arrayItem[1]])
})
// This will output to the sheet in three rows.
// [1][2]
// [3][4]
// [5][6]
Specific situation.. I'm having an array filled with datetimes I pull in via an api.
Users should be able to select a date from a datepicker (only showing dates available in the array) and afterwards see the corresponding time.
So what I've done..
The original array is obtained via php, so before starting to populate the datepicker with possible dates I create an extra array with dates only.
Since I maintain the key's it's possible to put these 2 arrays next to eachother.
Array looks as following:
["8-8-2017,07:00", "26-8-2017,07:00"];
So far so good...
After a user picks a date I trigger this to be able to start digging for the time corresponding that date.
Now it's getting messy...
$('#datepick').datepicker().on("input change", function(e) {
$("#uur").text('');
var selecteddate = e.target.value;
var searchArr = datesArray;
var ind = searchArr.indexOf(selecteddate.toString());
var result = datesArray.filter(function(item) {
return typeof item == 'string' && item.indexOf(selecteddate.toString()) > -1;
});
var afterComma = result.toString().substr(result.toString().indexOf(",") + 1);
var final = afterComma.replace(":", "u");
$("#uur").text("De warming up party gaat van start rond " + final);
});
The result is that this only works on the last element of the array.
Because I'm splitting based on the comma's. Now I know the easiest way to work arround this would be to change the , that's seperating date and time in another symbol but still I'm wondering why this couldn't be easier.
You convert whole array to string every time. You should change following code:
var afterComma = result.toString().substr(result.toString().indexOf(",") + 1);
To this;
var afterComma = item.toString().substr(item.toString().indexOf(",") + 1);
Edit:
I also missed the loop above
//for every item in result, afterComma will refer to related minute string
for (var item in result) {
var afterComma = item.toString().substr(item.toString().indexOf(",") + 1);
// Do rest here
}
I am trying to develop the addition program using column addition in javascript, For e.g: 53,22 , we add numbers from the right 3+2 and 5+2 finally results in 75, the main problem is with large numbers i am trying to develop a program which can implement addition of large numbers.so that i don't get gibberish like 1.26E+9, when adding large numbers. i tried doing it by defining the code like below
function add(a,b)
{
return (Number(a) + Number(b)).toString();
}
console.log(add('58685486858601586', '8695758685'));
i am trying to get the added number without getting the gibberish like 5.8685496e+16
You can add them digit by digit.
function sumStrings(a, b) { // sum for any length
function carry(value, index) { // cash & carry
if (!value) { // no value no fun
return; // leave shop
}
this[index] = (this[index] || 0) + value; // add value
if (this[index] > 9) { // carry necessary?
carry.bind(this)(this[index] / 10 | 0, index + 1); // better know this & go on
this[index] %= 10; // remind me later
}
}
var array1 = a.split('').map(Number).reverse(), // split stuff and reverse
array2 = b.split('').map(Number).reverse(); // here as well
array1.forEach(carry, array2); // loop baby, shop every item
return array2.reverse().join(''); // return right ordered sum
}
document.write(sumStrings('58685486858601586', '8695758685') + '<br>');
document.write(sumStrings('999', '9') + '<br>');
document.write(sumStrings('9', '999') + '<br>');
document.write(sumStrings('1', '9999999999999999999999999999999999999999999999999999') + '<br>');
I would keep all values as numbers until done with all the calculations. When ready to display just format the numbers in any way you want. For example you could use toLocaleString.
There are several libraries for that
A good rule of thumb is to make sure you do research for libraries before you actually go ahead and create you're own proprietary implementation of it. Found three different libraries that all solve your issue
bignumber.js
decimal.js
big.js
Example
This is how to use all three of the libraries, BigNumber coming from the bignumber.js library, Decimal from decimal.js and Big from big.js
var bn1 = new BigNumber('58685486858601586');
var bn2 = new BigNumber('8695758685');
console.log(bn1.plus(bn2).toString());
bn1 = new Decimal('58685486858601586');
bn2 = new Decimal('8695758685');
console.log(bn1.plus(bn2).toString());
bn1 = new Big('58685486858601586');
bn2 = new Big('8695758685');
console.log(bn1.plus(bn2).toString());
The console's output is :
58685495554360271
58685495554360271
58685495554360271
I want to implement a saving system similar to Imgur where if a user presses a button a unique 5 character value is returned. Here is what I have so far:
The database backend uses auto-incrementing ID's starting at 5308416. I use a modified Radix function (see below) to convert these numerical ID's into characters. I use a reverse function to lookup character ID's back to numerical database ID's.
function genID (value)
{
var alphabet = "23456789BCDFGHJKLMNPRSTVWXYZbcdfghjkmnpqrstvwxyz";
var result = "";
var length = alphabet.length;
while (value > 0)
{
result = alphabet[value % length] + result;
value = Math.floor (value / length);
}
return result;
}
The problem is that these generated ID's are very much predictable. My question is, how can I make the generated ID's seem random but still unique (so I can look them up in the database as numbers). I was thinking of using some encryption algorithm but not sure where to start. Any help or suggestions would be appreciated (maybe there is a better way of doing this also).
Do you have to be able to go both ways (i.e. convert an integer to it's hash and back again)? If you can store the hash and lookup the content that way, then it's relatively easy to create a function that produces a hard-to-guess, but complete hash space. You use primes to generate a sequence that only repeats once all possible permutations are exhausted.
The following PHP example is from my own code, adapted from this site:
function hash($len = 6) {
$base = 36;
$gp = array(1,23,809,28837,1038073,37370257 /*,1345328833*/);
$maxlen = count($gp);
$len = $len > ($maxlen-1) ? ($maxlen-1) : $len;
while($len < $maxlen && pow($base,$len) < $this->ID) $len++;
if($len >= $maxlen) throw new Exception($this->ID." out of range (max ".pow($base,$maxlen-1).")");
$ceil = pow($base,$len);
$prime = $gp[$len];
$dechash = ($this->ID * $prime) % $ceil;
$hash = base_convert($dechash, 10, $base);
return str_pad($hash, $len, "0", STR_PAD_LEFT);
}
It would be easy enough to implement that in JavaScript, but ideally you wouldn't need too - you'd have an insert trigger on your table that populated a hash field with the result of that algorithm (adapted for SQL, of course).
A non-predictable, but unique ID can be made by combining your server-side auto-incrementing number with either a current date/time nugget or with a random number. The server-side auto-incrementing number guarantees uniqueness and the date/time nugget or random number removes the predictability.
For a unique ID in string form that takes the server-side unique number as input and where you add the date/time nugget on the client you can do this:
function genID(serverNum) {
return(serverNum + "" + (new Date).getTime());
}
Or using a random number:
function genID(serverNum) {
return(serverNum + "" + Math.floor(Math.random() * 100000));
}
But, it might be best to add the date/time element on the server and just store that whole unique ID in the database there.