I am attempting to sort an array of timezone offsets that looks like the following:
["+03:00", "-11:00", "+05:00", "-04:00"]
This is just a subset of the array. All of the offsets for GMT based timezones are included. The logical ordering would be distance from GMT starting with -11.00
So the final correct ordering would be:
["-11:00", "-04:00", "+03:00", "+05:00"]
I'd have to use Array.prototype.sort here, but I'm not entirely sure what the most effective custom sort function to use here would be. Would it involve breaking the string up into two parts? eg: -|+ and offset, eg: 11, 4, 3, 5 and then comparing those? Is there a way to do it with less processing?
sort function should be
function(a, b) {
return parseFloat(a.replace(':', '.')) - parseFloat(b.replace(':', '.'));
}
basically, change the : to a . and return the difference in the resulting parsed floats
You can also do the following:
function(a, b) {
return parseInt(a.replace(':', ''), 10) - parseInt(b.replace(':', ''), 10);
};
This would convert the strings to +/-HHMM which you can then parse as an integer and still be able to support the not insubstantial number of non whole hour timezones. Though I don't think there's that much performance to be gained
Assuming that the timezones always end in :00 you can simply parseInt them:
["+03:00", "-11:00", "+05:00", "-04:00"].sort(
( a, b ) => (a, 10) > parseInt(b, 10)
);
parseInt will read a string up until it finds characters that don't look like numbers. For example parseInt('1a') returns 1. Since the first part of '-11:00' is a valid number ('-11'), parseInt will correctly read it.
Related
I have a number of seconds in a string, like: '5'.
From that I need to get the number of milliseconds and it has to be of type Number, like: 5000.
I know that you can easily convert strings to numbers by prefixing them with a +
const result = +'5';
console.log(result, typeof(result));
However playing around I saw that that's not even necessary because JavaScript automatically does the conversion for you when you try to use arithmetic between strings and numbers.
const result = '5' * 3;
console.log(result, typeof(result));
console.log('5.3' * 3);
On the docs I only found info about the Number() constructor.
My question is: is it safe to use arithmetic on strings (except for the addition)? Can I rely on the behaviour showed above?
Yes, it is safe. All arithmetic operations except a binary + will convert the operands to numbers. That includes bitwise operators as well as unary plus.
With that said, it is probably a good idea not to rely on this extensively. Imagine that you have this code:
function calculate(a, b) {
return a * 2 + b * 3;
}
//elsewhere in the code
console.log(calculate("5", "2"));
This works fine because both a and b are multiplied, so are going to be converted to numbers. But in six months time you come back to the project and realise you want to modify the calculation, so you change the function:
function calculate(a, b) {
return a + b * 3;
}
//elsewhere in the code
console.log(calculate("5", "2"));
...and suddenly the result is wrong.
It is therefore better if you explicitly convert the values to numbers if you want to do arithmetic. Saves the occasional accidental bug and it is more maintainable.
Yes, but you have to be careful...
console.log('5.3' * 3);
console.log('5.3' + 3);
These two very similar functions cast the values different ways:
* can only be applied between two numbers, so '5.3' becomes 5.3
+ can also concatenate strings, and the string comes first, so 3 becomes '3'
If you understand all these you can do this, but I'd recommend against it. It's very easy to miss and JS has a lot of weird unexpected casts.
I have strings of the format "10:30AM", "3:00PM" etc that I want to be able to use basic operations on, for example > or < and how many hours until say 10:30 based on current time. I would like to make the conversion on the client side (javascript/jQuery) prior to database insertion.
Should I convert these to javascript date-time objects? or would a regex to change it to say a number in 24hour time format be more suitable to perform these operations on? Or am I making this more difficult than it should be?
Thanks in advance.
You are going to want to convert to a date time -- there are a lot of edge cases when comparing numbers as strings -- much easier to just bite the bullet and make a date out of it. There are a million example libraries to use or take inspiration from.
I personally think if it is basic operations i would convert it to 24h and then compare. If it was anything more complex then I would convert it to a date-time object.
I would suggest you to use a library for that. I prefer Moment.js which allows you to perform compare or know how many hours from the current time.
It's a bit late but when you're sure you have such a specific string that needs converting in a specific way you could write your own implementation to convert the time, it'll be lighter and quicker to sort or compare:
var Time=function(time){
// TODO: you an check here what format the time variable
// is and if it's possible to convert it to time or milTime
this.time=time;
this.milTime=this.toMilTime();
this.val=this.setVal();
};
Time.prototype.toMilTime=function(){
return this.time.replace(/([0-9]{1,2}).([0-9]{1,2})([\w]{2})/,function(){
//TODO: put this in a try catch and check if hours and numbers
// are correct numbers. throw a new Error with the correct description
var hours=(arguments[1].length===1)?"0"+arguments[1]:
arguments[1],
minutes=(arguments[2].length===1)?"0"+arguments[2]:
arguments[2],
pam=arguments[3].toUpperCase();
if(pam==="PM"){
hours=parseInt(hours,10)+12;
}
return hours + ":" + minutes;
});
};
Time.prototype.setVal=function(){
return parseInt(this.milTime.replace(/:/,""),10);
}
// used for sorting
Time.prototype.valueOf=function(){
return this.val;
};
// needed for <> comparison
Time.prototype.toString=function(){
return this.milTime;
};
var t = new Time("10:30AM"),
t1=new Time("1:00PM"),
t2=new Time("10:30AM");
console.log(t.milTime,t1.milTime);
console.log(t>t1);// this will use toString()
console.log(t1>t);// this will use toString()
console.log(t===t2);//false
console.log(t==t2);//false
console.log(t.milTime===t2.milTime);//true
var arr=[t,t1,t2].sort(function(a,b){
return a.valueOf()-b.valueOf();// force it to use valueOf
});
console.log(arr);
alert('g' - 'a') is returning Not a Number. ('NAN').
But I expect, to get the difference between ascii as alert(103-97) => alert(6). Hence 6 to be output.
In C, int i = 'g' - 'a', will give i = 6.
How to achieve this subtraction of 2 characters in javascript? (easily without much effort as below)
alert("g".charCodeAt(0) - "a".charCodeAt(0)) is giving 6.
Application : I am using this in chess program.
The only practicable way to do as you want is the way you've already suggested:
alert('g'.charCodeAt(0) - 'a'.charCodeAt(0));
As you know, this will retrieve the ASCII character code from 0th element of the string in each case, and subtract the second from the first.
Unfortunately this is the only way to retrieve the ASCII code of a given character, though using a function would be somewhat simpler, though given the brevity/simplicity of the charCodeAt() solution not all that much so.
References:
String.charCodeAt().
JavaScript doesn't treat characters as numbers; they are single-character strings instead. So the subtract operator will be calculating Number('g') - Number('a').
You should do 'g'.charCodeAt(0) - 'a'.charCodeAt(0) (there is no better way, but you can wrap it in a function)
You can write yourself a custom function. Something like this:
function asciiDif(a,b) {
return a.charCodeAt(0) - b.charCodeAt(0);
}
And then:
alert(asciiDif('g','a'));
Is there a way to force .getRange().getValues() to return an int? Although only numbers exist in my range, it is returning them as strings. I would like to avoid using parseInt in every one of my statements or creating a separate array with converted values.
Or is that the only solution, to get the array and then parseInt the entire array in a loop?
you can do this easily using the unary '+' operator as follows:
First get your values from your spreadsheet using getValue() or getValues(). Suppose you get two such values, and store them in A = 1 and B = 2. You can force them to be recognized as numbers by using any math binary operator except for +, which concatenates strings, so A - B = -1, while A + B will return '12'.
You can force the variables to be numbers simply by using the + unary operator with any variable that might be interpreted as a string. For example, +A + +B will return the correct value of 3.
You can use parseInt() or Number()
example
var A='12';var B=5
A+B = 125
parseInt(A)+B = 17
Number(A)+B = 17
That said, getValues() is not supposed to return strings unless values have some space or other non-numeric characters in it... are these values entered manually or come as a result of some function ?
getValues() returns a 2D array of Objects - so these are Strings, Integers or Date objects depending on what these are formatted as in your spreadsheet.
Go back to your spreadsheet and see what the cells that have integer values are formatted as. Format them as integers and you should get back integers.
I was beginning to write a bubble sort for this when I thought maybe there is a way to use a function with array.sort() that does the job ?
Here is a (hopefully) clear example of what I have to sort : (file names list)
var array = ['impression_page_1_12_juin','impression_page_1_13_juin','impression_page_2_12_juin','impression_page_2_13_juin']
As you can see there are 2 'page1' on 2 different dates, only characters 19 and 20 in each string are different. I'd like to sort on those 2 characters.
Can Javascript do that straightforward or should I return to my substrings and bubble sort method ?
Use the sort method with a function for the comparison:
array.sort(function(x,y){
var xp = x.substr(18, 2);
var yp = y.substr(18, 2);
return xp == yp ? 0 : xp < yp ? -1 : 1;
});
Yes, you can pass a function to array.sort that compares the two strings according to whatever criteria you're interested in. See How to sort array in javascript?
You will have to be careful with strings vs. numbers: '1_12' < '1_2' is True, for instance. If you need to compare them as numbers, you could split the strings, do parseInt on each part, and implement a pairwise comparison.