There is an array:
var a = new Array();
It contains date entries like this: '2012-09-12 09:20', etc
I need to find minimum and maximum dates using javascript. This code does not work with time values.
var minT = Math.min.apply(Math, a);
var maxT = Math.max.apply(Math, a);
How can I solve this problem in javascript? It seems to be quite complex as I'm not very experienced in this language.
If your array contains Date objects, then this should work. If it just contains strings like '2012-09-12 09:20', then you can sort them, and get the 1st and last elements.
a.sort(function(a, b){
return Date.parse(a) - Date.parse(b);
});
var maxT = a[a.length-1];
var minT = a[0];
Math.min/max only compares numbers, not strings. Don't use them to represent the dates, but use Date objects - they will be compared by their internal timestamp number. Still, the max/min will return that internal number, so you would need to convert it back to a Date (see Min/Max of dates in an array?):
However, if you want to use the strings or can't use the recreated Date, you will need to run manually through the array - either with a for-loop, or the ES5.1-only iterator method .reduce():
var min = datestrings.reduce(function(min, cur) {
return cur < min ? cur : min;
});
// is equivalent to
var min = datestrings[0];
for (var i=1; i<datestrings.length; i++)
if (datestrings[i] < min)
min = datestrings[i];
If your code does not need to be efficient, you also just can sort the array and get the first and last values. The default alphanumeric sorting will do it for your date format, so this is really simple:
datestrings.sort();
var min = datestrings[0],
max = datestrings[datestrings.lengh-1];
Try this:
var maxDate=new Date(Math.max.apply(null,dates));
var minDate=new Date(Math.min.apply(null,dates));
I found it on an earlier question
This should do it:
var maxT=new Date(Math.max.apply(null,a));
var minT=new Date(Math.min.apply(null,a));
If you must work with strings you could define a function:
function maxDate(data){
var max = '';
for(var i=0; i<data.length; i++)
if(data[i]>max)
max=data[i];
return max;
}
And then:
var maxT=maxDate(a);
DISCLAIMER: This second method will only work if all the date strings are in the same format, if you have different format dates in your array you will not be able to use this function.
Is the array filled with Date objects?
If so, compare them using them, and sort them using one of the many known algorithms.
If not, recreate the array with Date objects, one for each of them, and do as I said above, by ordering the array.
Related
I'm finding an equivalent to Java's DecimalFormat in JavaScript. I would like to format given numeric values with given decimal pattern like
"#,###.00"
"###.##"
"#,###.##"
"$#,##0.00"
"###,###.00"
"$###,###.00"
"###,###.###"
"####,####.000"
Has there any way to achieve it?
Part 1 - formatting
I would recommend using the Intl.NumberFormat natively supported in javascript, although it may not be supported by older browsers. Looks like IE11 has it, but not android.
So if you wanted to support US Dollars you would simply use something like this
var dollarFormat = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' });
var amountInDollars = dollarFormat.format(123456.123);
// amountInDollars = "$123,456.12"
But this also rounds up for you, for example
var roundedDollars = dollarFormat.format(555.555);
// roundedDollars = "$555.56";
For the numeric cases just use a different formatter. The default 'en-US' adds commas, a decimal before fractional numbers, and limits to 3 fractional numbers. But this is configurable.
var numberFormat = new Intl.NumberFormat('en-US');
var formatted = numberFormat.format(123456.123456);
// formatted = "123,456.123"
var numberFormat2decimals = new Intl.NumberFormat('en-US', { maximumFractionDigits: 2 });
var formatted2 = numberFormat2decimals.format(123456.123456);
// formatted2 = "123,456.12"
You can set maximum and minimum for fraction, integer, and significant digits, and this also supports international formats. Since it's native javascript, I think it's a good way to go if your platforms support it.
MDN is an excellent reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat
Part 2 - the 0's
To achieve the 0's in your formats you'll have to modify the value before passing to the formatter. If you require a minimum fractional amount, you're fine for things like .00, the currency formatter will do that by default. If you've got fractal numbers you don't want, just use Math.trun() to truncate the values.
var num = Math.trun(1234.1234);
// num = 1234
Now to change something like 12345 to 12340 we'll have to remove some of the numeric value. We can find out much by converting to a string, pulling the last character, and converting back.
var num = 123456.12345;
var wholeNum = Math.trunc(num);
// wholeNum = 123456;
var toRemove = Number.parseInt(wholeNum.toString().slice(-1), 10);
// toRemove = 6
// slice(-1) gives us the right-most character of a string.
// Notice the ', 10' at the end, this is important to indicate which number base to use for parseInt.
var wholeNumEnding0 = wholeNum - toRemove;
// wholeNumEnding0 = 123450
Hopefully that's what you're looking to accomplish? I didn't perform any rounding here.
Note: I typed this at speed, excuse any mistakes, there might be better ways to do it too.
If you don't want to rely on a library, you could do something like the following:
var number = 100000.00000000000012422;
function FormatNumber(no){
no = no.toFixed(2);
no = no.toString().split('.');
var p1 = no[0];
p1 = p1.substring(0, p1.length - 3) + ',' + p1.substring(p1.length - 3);
no = p1 + '.' + no[1];
console.log(no);
}
FormatNumber(number);
The FormatNumber function takes a number as a parameter (you would probably want to expand that to include e.g. decimal places). It converts the number to the required decimal places, the turns it into a string and splits it by the decimal separator '.'.
The next step is to add a thousands separator three characters from the back, then it's just a matter of joining the remaining characters back together.
JSFiddle
If you wanted to get a ',' every 3 characters you could write a little more 'complex' formatter, something along the lines of the following:
no = no.toFixed(2);
no = no.toString().split('.');
var p1 = no[0];
var arr = [];
arr = p1.split("").reverse().join("").match(/[\s\S]{1,3}/g) || [];
arr = arr.reverse();
p1 = "";
for(var i = 0; i < arr.length; i++){
p1 += arr[i].split("").reverse().join("");
if(i != arr.length - 1){
p1 += ',';
}
}
no = p1 + '.' + no[1];
This method splits the number into an array by each number, reverses the array as we need to start from the end of the string to get accurate result.
Then we iterate the array of strings with 3 or less values by splitting the number into an array again, reversing it and joining back together and then appending to p1. If it's the last item, it doesn't add a comma.
Lastly we take the decimal and append to built string.
JSFiddle
I get a date range from some API (not in my control) which has the following possibilities of date format
dd-Mmm-yy
dd-Mmm-yyyy
dd/mm/yy
dd/mm/yyyy
mm/dd/yy
mm/dd/yyyy
yyyy-mm-dd
So I get the date range as
01-Dec-16-06-Dec-16 (as per dd-Mmm-yy) OR
01/12/16-06/12/16 (as per dd/mm/yy)
So hyphen (-) is the from/to date separator which the API uses (not in my control) & I get this single combined value
Now, in my code, I want to get the from & to dates separately.
So I use
range.split("-")
However, this does not work properly for 01-Dec-16-06-Dec-16
Not sure what is the best way to account for all the possibilities (considering that the from/to date separator would always be -)
Since this is a case of an ugly API, the only way to do this is by using "hacky" solutions.
Use #Rory McCrossan's suggestion: count the number of - in the string. If 1, split. If 5, split by the third.
Since the API uses the same format of date for both the left side and the right side, the total length of the string will always be ("left side" + "-" + "right side"). You can split the text on the middle character.
e.g.
let date = "01-Dec-16-06-Dec-16";
let idx = date.length / 2;
let start = date.substr(0, idx);
let end = date.substr(idx + 1);
Use regex.
From the formats provided, it looks like the from and to dates will always be the same length split by -. In that case, just do this:
var len = (yourDateRange.length - 1) / 2
var dateFrom = yourDateRange.substring(0, len)
var dateTo = yourDateRange.substring(len + 1)
If you have any format where the length is variable (Such as full name for month), this obviously won't work
It's a bit hacky, but gets the job done.
I used a chained indexOf call with the previous call as the fromIndex parameter (which is the 2nd parameter of indexOf). And seeing as there is either / in the string (then split by -) or not (then split by 3rd -), there was no need for any special checks.
function splitDates(date) {
// ~ is just a fancy way to turn indexOf into a
// boolean-equivalent check (-1 is 0, 0 is 1, etc)
if (~date.indexOf('/')) {
return date.split('-');
} else {
var idx = date.indexOf('-', 1 + date.indexOf('-', 1 + date.indexOf('-')));
return [date.slice(0, idx), date.slice(idx + 1)];
}
}
var dates = ['01-Dec-16-06-Dec-16', '01/12/16-06/12/16'];
dates.forEach((date) => {
alert(splitDates(date))
});
I need to sum all of the values of a key "number" from several objects within an array. What would be the correct way to do this? This is what I've tried.
var numarray = [{"number":"10"},{"number":"2"},{"number":"5"},
{"number":"3"},{"number":"21"},{"number":"43"},{"number":"30"}];
function Sum() {
var sum;
for (number in numarray[i]){
alert(sum); //sum would be the result I need to get
}
}
Use forEach to loop through each of the json object.
Use parseInt to convert the values to integer
var numarray = [
{"number":"10"},
{"number":"2"},
{"number":"5"},
{"number":"3"},
{"number":"21"},
{"number":"43"},
{"number":"30"}];
function Sum(){
var sum=0;
numarray.forEach(function(item){
sum += parseInt(item.number)
})
document.write('<pre>'+sum+'</pre>')
}
Sum()
DEMO
EDIT
When using parseInt it is better to specify the radix
parseInt(item.number,10)
Using a 10 radix means the number is parsed with a base 10 and thus turns the number into the integer .If parseInt detects a leading zero it will parse the number in octal base
Using Number
Number(item.number)
It will not detect any any octal
You can use reduce for this:
Here's how you would normally find the sum of elements in an array:
var sum = arr.reduce(function(a,b) {
return a + b;
});
Since you have an array of objects, you'll need to change this to something like:
var sum = arr.reduce(function(a,b) {
return parseFloat(a) + parseFloat(b.number);
}, 0);
Notice the 0 I've added added as a parameter? It's the default parameter and required in this case.
the title may be a bit confusing but I'll explain it in detail. I have a table in UI and user can choose date ranges from there like;
monday - {in:"13:00:00",out:"13:59:59"}
tuesday - [{in:"13:00:00",out:"13:59:59"},{in:"14:00:00",out:"14:59:59"}]
user can only choose multiple hour intervals for one day. I already made the grouping the intervals according to their date and combining the intervals like
tuesday- [{in:"13:00:00",out:"14:59:59"},{in:"14:00:00",out:"14:59:59"}]
in the first iteration. But I couldn't figure out how to make it for more than 4 or 5 hour intervals.FYI I'm using lodash for sorting and grouping and moment for converting hours to int.
If user enters 5 intervals for tuesday like [{in:"13:00:00",out:"13:59:59"},{in:"14:00:00",out:"14:59:59"},{in:"15:00:00",out:"15:59:59"},{in:"18:00:00",out:"18:59:59"},{in:"19:00:00",out:"19:59:59"}]
I want ranges to be combined like ;
[{in:"13:00:00",out:"15:59:59"},{in:"18:00:00",out:"19:59:59"}]
Any help or suggestion will be appreciated.
Assuming that your input data is chronological then one way of implementing your reduced time table is this;
var timeSlices = [{in:"13:00:00",out:"13:59:59"},{in:"14:00:00",out:"14:59:59"},{in:"15:00:00",out:"15:59:59"},{in:"18:00:00",out:"18:59:59"},{in:"19:00:00",out:"19:59:59"}],
ts = new Date(),
te = new Date(),
reduced = timeSlices.reduce((p,c) => {p.length ? (ts.setHours(...p[p.length-1].out.split(":")),
te.setHours(...c.in.split(":")),
te-ts <= 1000 ? p[p.length-1].out = c.out
: p.push(c))
: p.push(c);
return p;},[]);
console.log(reduced);
However if the objects with in and out times are located arbitrary in the array then a more conceptual approach like first sorting them according to their in times would be essential. That wouldn't be a big deal though.
Assuming ranges are composed of Moment instances and you wanted to combine any two ranges where the end of one range either overlapped another range or was less than or equal to one second behind the start of another range, this function should be able to combine the ranges
function combineRanges (ranges) {
if (ranges.length <= 1) {
return ranges
}
ranges = ranges.sort(byStart)
var current = ranges[0]
var combined = [current]
for (var i = 1; i < ranges.length; i++) {
var next = ranges[i]
if (current.out.diff(next.in, 'seconds') > 1) {
combined.push(next)
current = next
} else if (current.out.isBefore(next.out)) {
current.out = next.out
}
}
return combined
}
function byStart (a, b) {
return a.in - b.in
}
var number = 342345820139586830203845861938475676
var output = []
var sum = 0;
while (number) {
output.push(number % 10);
number = Math.floor(number/10);
}
output = output.reverse();
function addTerms () {
for (i = 0; i < output.length; i=i+2) {
var term = Math.pow(output[i], output[i+1]);
sum += term;
}
return sum;
}
document.write(output);
document.write("<br>");
document.write(addTerms());
I am trying to take that large number and split it into its digits. Then, find the sum of the the first digit raised to the power of the 2nd, 3rd digit raiseed to the 4th, 5th raised to the 6th and so on. for some reason, my array is returning weird digits, causing my sum to be off. the correct answer is 2517052. Thanks
You're running into precision issues within JavaScript. Just evaluate the current value of number before you start doing anything, and the results may surprise you:
>>> var number = 342345820139586830203845861938475676; number;
3.423458201395868e+35
See also: What is JavaScript's highest integer value that a Number can go to without losing precision?
To resolve your issue, I'd store your input number as an array (or maybe even a string), then pull the digits off of that.
This will solve your calculation with the expected result of 2517052:
var number = "342345820139586830203845861938475676";
var sum = 0;
for(var i=0; i<number.length; i=i+2){
sum += Math.pow(number.charAt(i), number.charAt(i+1));
}
sum;
JavaScript stores numbers in floating point format (commonly double). double can store precisely only 15 digits.
You can use string to store this large number.
As mentioned, this is a problem with numeric precision. It applies to all programming languages that use native numeric formats. Your problem works fine if you use a string instead
var number = '342345820139586830203845861938475676'
var digits = number.split('')
var total = 0
while (digits.length > 1) {
var [n, power] = digits.splice(0, 2)
total += Math.pow(n, power)
}
(the result is 2517052, byt the way!)
Cast the number as a string and then iterate through it doing your math.
var number = "342345820139586830203845861938475676";//number definition
var X = 0;//some iterator
var numberAtX = 0 + number.charAt(X);//number access
The greatest integer supported by Javascript is 9007199254740992. So that only your output is weird.
For Reference go through the link http://ecma262-5.com/ELS5_HTML.htm#Section_8.5
[edit] adjusted the answer based on Borodins comment.
Mmm, I think the result should be 2517052. I'd say this does the same:
var numbers = '342345820139586830203845861938475676'.split('')
,num = numbers.splice(0,2)
,result = Math.pow(num[0],num[1]);
while ( (num = numbers.splice(0,2)) && num.length ){
result += Math.pow(num[0],num[1]);
}
console.log(result); //=> 2517052
The array methods map and reduce are supported in modern browsers,
and could be worth defining in older browsers. This is a good opportunity,
if you haven't used them before.
If you are going to make an array of a string anyway,
match pairs of digits instead of splitting to single digits.
This example takes numbers or strings.
function sumPower(s){
return String(s).match(/\d{2}/g).map(function(itm){
return Math.pow(itm.charAt(0), itm.charAt(1));
}).reduce(function(a, b){
return a+b;
});
}
sumPower('342345820139586830203845861938475676');
alert(sumPower(s))
/*
returned value:(Number)
2517052
*/