Why isn't this sorting correctly? - javascript

So I'm attempt to take an array like
["2015/10","2015/1","2015/6","2015/12","2015/3","2015/7","2015/2","2016/1","2015/8","2015/5","2015/11","2015/9","2015/4"]
, where the XXXX/YY is year/month format, and sort it from least to greatest.
Attempt, using https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort as a reference:
month_keys.sort(function(x,y){
var partsX = x.split('/'), partsY = y.split('/');
return partsX[0] < partsY[0] ? -1 : ( partsX[1] < partsY[1] ? -1 : 1 );
})...
and that gives me
["2015/1","2015/11","2016/1","2015/10","2015/12","2015/2","2015/3","2015/5","2015/5","2015/6","2015/7","2015/8","2015/9"]
in the example array I gave at the beginning. What am I doing wrong?

You are comparing strings, not numbers. When comparing strings, they are compared char by char so anything starting with an 1 comes before something starting e.g. with a 2. Even if it's 10 vs 2.
Convert them to numbers and you should get the order you want:
var partsX = +x.split('/'),
partsY = +y.split('/');
You also need to fix the actual comparison:
if (partsX[0] < partsY[0]) return -1;
else if (partsX[0] > partsY[0]) return 1;
else if (partsX[1] < partsY[1]) return -1;
else if (partsX[1] > partsY[1]) return 1;
else return 0;

You have strings representing numbers. Just put a '+' before the variable to convert it to number:
return +partsX[0] < +partsY[0] ? -1 : ( +partsX[1] < +partsY[1] ? -1 : 1 );
I works...

Related

Each digit differs from the next one by 1

Script has to work this way:
isJumping(9) === 'JUMPING'
This is a one digit number
isJumping(79) === 'NOT JUMPING'
Neighboring digits do not differ by 1
isJumping(23454) === 'JUMPING'
Neighboring digits differ by 1
I have:
function isJumping(number) {
let str = number.toString();
for (let i = 1; i < str.length; i++) {
if (Math.abs(str[i+1]) - Math.abs(str[i]) == 1){
return 'JUMPING';
}
}
return 'NOT JUMPING';
}
console.log(isJumping(345));
Help please, where is mistake?
Loop over the characters and early return with "NOT JUMPING" if the condition is violated & if the condition is never violated return "JUMPING".
function isJumping(num) {
const strNum = String(Math.abs(num));
for (let i = 0; i < strNum.length - 1; i++) {
if (Math.abs(strNum[i] - strNum[i + 1]) > 1) {
// replace `> 1` with `!== 1`, if diff 0 is not valid!
return "NOT JUMPING";
}
}
return "JUMPING";
}
console.log(isJumping(9));
console.log(isJumping(79));
console.log(isJumping(23454));
There are a couple of issues:
You're not handling single digits.
You're returning too early. You're returning the first time you see a difference of 1 between digits, but you don't know that subsequent differences will also be 1.
You're not checking the difference between the first and second digits, and you're going past the end of the string.
You're using Math.abs as a means of converting digits to numbers.
Instead (see comments):
function isJumping(number) {
let str = number.toString();
for (let i = 1; i < str.length; i++) {
// Convert to number, do the difference, then
// use Math.abs to make -1 into 1 if necessary
if (Math.abs(+str[i] - str[i-1]) !== 1) {
// Found a difference != 1, so we're not jumping
return "NOT JUMPING";
}
}
// Never found a difference != 1, so we're jumping
return "JUMPING";
}
console.log(isJumping(345)); // JUMPING
console.log(isJumping(9)); // JUMPING
console.log(isJumping(79)); // NOT JUMPING
console.log(isJumping(23454)); // JUMPING
In that, I use +str[i] to convert str[i] to number and implicitly convert str[i-1] to number via the - operator, but there are lots of ways to convert strings to numbers (I list them here), pick the one that makes sense for your use case.
You might also need to allow for negative numbers (isJumping(-23)).
A clumsy way would be if (Math.abs(Math.abs(str[i+1]) - Math.abs(str[i])) == 1). Right now you are using Math.abs() to convert digits to numbers. Also, indexing is off, you start from 1, which is good, but then you should compare [i] and [i-1]. And the usual mismatch: you can say "JUMPING", only at the end. So you should check for !==1, and return "NOT JUMPING" inside the loop, and "JUMPING" after. That would handle the 1-digit case too.
It's a more readable practice to use parseInt() for making a number from a digit, otherwise the implementation of the comment:
function isJumping(number) {
let str = number.toString();
for (let i = 1; i < str.length; i++) {
if (Math.abs(parseInt(str[i-1]) - parseInt(str[i])) !== 1){
return 'NOT JUMPING';
}
}
return 'JUMPING';
}
console.log(isJumping(345));
console.log(isJumping(3));
console.log(isJumping(79));
You just need to check your single digit case, and then see if all the digits vary by just 1
function isJumping(number) {
let str = number.toString();
if(str.length == 1)
return 'JUMPING'
const allByOne = str.substring(1).split('').every( (x,i) => {
var prev = str[i];
return Math.abs( +x - +prev) == 1
})
return allByOne ? 'JUMPING' : 'NOT JUMPING';
}
console.log(isJumping(9));
console.log(isJumping(79));
console.log(isJumping(23454));
A vaguely functional approach... The find gets position of the first character pair where the gap is more than one. The .filter deals with negatives (and other extraneous characters) by ignoring them.
// default b to a, so that last digit case, where b===undefined, gives true
const gapIsMoreThanOne = (a,b=a) => ( Math.abs(a-b)>1);
const isDigit = n => /[0-9]/.test(n);
const isJumping = n => n.toString()
.split("")
.filter(isDigit)
.find((x,i,arr)=>gapIsMoreThanOne(x,arr[i+1]))
=== undefined
? "JUMPING" : "NOT JUMPING"
;
console.log(isJumping(1)); // JUMPING
console.log(isJumping(12)); // JUMPING
console.log(isJumping(13)); // NOT JUMPING
console.log(isJumping(21)); // JUMPING
console.log(isJumping(21234565)); // JUPING
console.log(isJumping(-21234568)); // NOT JUMPING
console.log(isJumping("313ADVD")); // NOT JUMPING
PS: To me "JUMPING" implies that there is a gap greater than one, not that there isn't: but I've gone with how it is in the question.

Check if a string starts with a number in range

I have a string that can be of random length and I need to check if it satisfies the following conditions:
starts with 4 digits
the first 4 digits form a number in range 2221-2720 (credit card number)
Right now I have the following code:
var isCardNumber = function (myString)
{
var num = parseInt(myString.substr(0, 4));
if(num) {
return num >= 2221 && num <= 2720;
};
return false;
};
Can this be done simpler/shorter? Probably with a regexp?
var isCardNumber = function ( cardNumber ) {
var n = +cardNumber.substr( 0, 4 )
return n && n > 2220 && n < 2721
}
Here is a regex for your general culture. As other said, I would not recommend using it. You could do performance tests but I'd expect it to be slower than the integer comparison test.
^2(2[2-9]\d|[3-6]\d\d|7([0-1]\d|2[0-1]))
To construct this kind of regex you need to break your range into easily reprensentable strings ; 2221-2720 is :
2220 to 2299 (22[2-9]\d)
2300 to 2699 (2[3-6]\d\d)
2700 to 2719 (27[0-1]\d)
2720 to 2721 (272[0-1])
Then you can factorise it as I did or just use it as is, with each fragment separated by a |.

sort an alphanumeric array

I have an array that contains numbers and strings:
disorderedArray = ["74783 Banana", "38903 Orange", "94859 Apple"];
I needed to put them in ascending order by number. I found an example that worked well for descending Sort Alphanumeric String Descending
However, I can't seem to change the return line to make the array ascending. I tried to put arr.reverse(); after the return line, but that seemed kind of hackish and it didn't work anyways. I also changed the > and < symbols in the return line, but I started to get crazy results.
function sort() {
var arr=disorderedArray;
arr.sort(function(a,b){
a=a.split(" ");
b=b.split(" ");
var an=parseInt(a[0],10);
var bn=parseInt(b[0],10);
return an<bn?1:(an>bn?-1:(a[1]<b[1]?-1:(a[1]>b[1]?1:0)));
arr.reverse();
});
console.log(arr);
}
The callback function returns positive or negative values depending on the comparison of the values. Just change the sign of the -1 and 1 values that are returned:
return an<bn?-1:(an>bn?1:(a[1]<b[1]?1:(a[1]>b[1]?-1:0)));
Here is a more readable way to write the same:
return (
an < bn ? -1 :
an > bn ? 1 :
a[1] < b[1] ? 1 :
a[1] > b[1] ? -1 :
0
);
Note that the original code sorts the numeric part descending and the rest of the string ascending, so this does the opposite. The value from the first two comparisons determine how the numeric part is sorted, and the last two determine how the rest of the strings are sorted, so you can adjust them to get the desired combination.
sort's function is just to sort. You need to call reverse on the sorted array.
function sort() {
var arr = disorderedArray;
arr.sort(function(a, b) {
a = a.split(" ");
b = b.split(" ");
var an = parseInt(a[0], 10);
var bn = parseInt(b[0], 10);
return an < bn ? 1 : (an > bn ? -1 : (a[1] < b[1] ? -1 : (a[1] > b[1] ? 1 : 0)));
});
console.log(arr.reverse());
}

Function that returns arbitrary decimal place on javascript

I want to make some function on javascript,
that receives some number and position number n and returns its nth decimal place.
That is,
nthdigit(3.5852,2) = 8
nthdigit(3.5852,3) = 5
nthdigit(3.5852,5) = 0
nthdigit(9.772,1) = 7
How can I do this correctly? Thanks.
Pure math solution:
function decimaldigit(num, n) {
return Math.floor(num * Math.pow(10, n)) % 10;
}
Convert the number to a String, split it on the decimal ., take the character you want and convert it back to a number.
function nthdigit(number, i) {
var afterDecimal = number.toString().split(".")[1];
return parseInt(afterDecimal.charAt(i-1));
}
I've chosen charAt(i-1) because character are counted starting 0 and it feels more natural in this case when you want the first number to put in 1.
This should be very easy to solve:
var nthdigit function(decimal, n)
{
var dec = '' + decimal; //convert to string
var decimalString = dec.split('.')[1]; //covert to array, take element with index [1]
var decimalPlaces = decimalSting.split(''); //covert to array
return parseInt(decimalPlaces( n-1 )); //1. decimalPlace has index 0
}
Another pure math solution, with better precision for high numbers and correct handling of negative numbers:
function nthdigit(num, n) {
return n ? nthdigit((num % 1) * 10, n-1) : Math.trunc(num);
}
using Math.trunc:
if (typeof Math.trunc != "function")
Math.trunc = function trunc(value) {
return value === 0 ? value : !isFinite(value) ? value : value | 0;
}

Compare two floats in JavaScript

How can I compare two floats in JavaScript? Or perhaps a float and an int.
if (5 > 4.3.3)
if (5.0 > 5.3)
Thankful for all input!
Update
I need to for an iPhone app that I am developing in Appcelerator. I need to compare iOS versions and display different content to each. So if a device is running 5.0 and another is running 4.3.3 I need to know the difference in my code.
Just like that.
if (5.0 > 5.3)
In your 1st example you do not have a valid number [4.3.3].
You may use something along the lines of http://maymay.net/blog/2008/06/15/ridiculously-simple-javascript-version-string-to-object-parser/
Basically he uses:
function parseVersionString (str) {
if (typeof(str) != 'string') { return false; }
var x = str.split('.');
// parse from string or default to 0 if can't parse
var maj = parseInt(x[0]) || 0;
var min = parseInt(x[1]) || 0;
var pat = parseInt(x[2]) || 0;
return {
major: maj,
minor: min,
patch: pat
}
}
Basic comparator can look like:
1. Convert to correct positional structure
2. Compare lengths
3. Compare values
function compareVer(a, b, sep = '.') {
// 1. Convert to correct positional structure
const aP = a.split(sep);
const bP = b.split(sep);
// 2. Compare lengths
if (aP.length > bP) return 1;
if (bP.length > aP) return -1;
for (let i = 0; i < aP.length; ++i) {
// 3. Compare values
// You can add necessary type conversions
// Ex.: add parseInt, if you want to support `001=1` and not `3f=3f`
if (aP[i] > bP[i]) return 1;
if (bP[i] > aP[i]) return -1;
}
return 0;
}
console.log(compareVer('5', '4.3.3')); // 1 gt
console.log(compareVer('5.0.2', '5.0.2')); // 0 eq
console.log(compareVer('5.0', '5.3')); // -1 lt

Categories

Resources