Explain this sorting in JavaScript - javascript

var a = ['a100', 'a1', 'a10'];
a.sort();
This logs: ["a1", "a10", "a100"]
var a = ['f_a100_', 'f_a1_', 'f_a10_'];
a.sort();
But this logs: ["f_a100_", "f_a10_", "f_a1_"]
Can you please advise me why is that?

Array.sort sorts value by converting the item to string and then doing a lexicographical sort.
Now, by lexicographical sorting all that they mean is that they compare the string characters one by one till a non matching character is found. The position of the non matching character in the character-set (where letters are ordered alphabetically) decides the rank of the string.
f_a100_
^
f_a1_
^
f_a10_
^
See the first non matching character. Here _ is greater than 0 (check their ascii codes) so f_a100_ and f_a10_ comes above f_a1_. Now between those two we go to the next character
f_a100_
^
f_a10_
^
Here, applying the same logic f_a100_ comes first. So the final order is ["f_a100_", "f_a10_", "f_a1_"]
This sorting order would seem logical for simple strings. But for certain other cases like yours it works weirdly because of the way the charsets are arranged. To get a desired behaviour you should write your own compare function that strips out the number part and return a positive, negative or 0 value as shown in the example.

Javascript sorting is string based:
var a = ['a100', 'a1', 'a10'];
a.sort();
Will return:
["a1", "a10", "a100"]
Because of string comparison: "a1" < "a10" < "a100". In the other example, "f_a100_" < "f_a10_" because "0" < "_", and "f_a10_" < "f_a1_" for the same reason.
Indeed this:
[15, 13, 8].sort();
will return:
[13, 15, 8]
This is something a little weird, but that's how it's designed. If you want to change the ordering criteria you can pass a function as a parameter. E.g. (From here)
var points = [40,100,1,5,25,10];
points.sort(function(a,b){return a-b});

The javascript sort function does sorting alphanumerically not arithmetically so you get the results such. See this question that is almost same with yours Array Sort in JS

In the first case "a1" < "a10" because when comparing two strings the "a1" portion matches but then it decides that "a1" has a shorter length.
But in the second case "f_a1_" > "f_a10_", because when comparing these two the "f_a1" portion matches and then "_" is compared to "0". And '_' > '0' because they are compared by their ascii value.

Array.sort uses string sorting (even if the array is a list of numbers).
The sorting you're looking for is known as natural order sorting. In this sorting numbers are treated as numbers, 100 comes after 10, 2 comes before 10 etc.
JavaScript does not natively have a natsrt. I have written my own implementation but it's quite involved. Here is a reference implementation: http://phpjs.org/functions/strnatcmp/
If you just need to sort strings of the form f_a[0-9]+_ you can write a regular expression to extract the number part.

Related

Can someone explain the difference between these JS functions one with callback and other no with callback

To sort an array we can do:
1.
var values = [0,3,2,5,7,4,8];
console.log(values.sort());
2.
var values = [0,3,2,5,7,4,8];
values.sort(function(v1,v2){
return v1-v2;
});
console.log(values);
Both give the same output, but which one is faster or better?
They're not equivalent unless all the numbers in the array have the same number of digits. The default comparison function for sort() compares the array elements as strings, not as numbers, and the string "10" is less than "2". You can see the difference if you add a 2-digit number to the array.
var values = [0,3,2,5,7,4,8, 10];
console.log(JSON.stringify(values.sort()));
console.log(JSON.stringify(values.sort(function(v1,v2){
return v1-v2;
})));
Comparing their performance seems pointless, since they do different things, and it's likely that the first form is simply wrong.
So the first .sort() call uses the default comparer, which can be found referenced in this documentation.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
"If compareFunction is not supplied, elements are sorted by converting them to strings and comparing strings in Unicode code point order."
The second sort uses your custom comparer, which does an integer comparison instead of string comparison.
The second should be faster since it doesn't need to do the string conversion on top of the comparisons.

time complexity for comparing two strings

How is the running time of the ff function o(nlogn)?
function isPermutation(a, b) {
if (a.length !== b.length) {
return false;
}
return a.split("").sort().join() === b.split("").sort().join();
}
aren't you checking the length of both strings, or is it dependent on the implementation of sort?
According to definition of Permutation, a String is permutate of another String if and only if all chars in the first String are also in the second String.
Example: "answer" is permutate of "awerns".
So to write an algorithm that checks if one string is permutate of another string all you have to do is:
Check if length of the two strings is same, return false if they are not same.
For each letter in String one check if it also exists in String two.
The above algorithm's running time will be but you can use sorting to solve same problem:
Check if length of two strings is same, return false if they are not same.
Sort the two strings
Each char in the Strings sequentially, like stringOne[i] == stringTwo[i]
So in this one if you use good sorting algorithm like Quick Sort or Merge Sort the overall running time will be

Why does isNaN() returns inconsistent results for strings?

Please consider following examples.
In this case isNaN returns false
> isNaN('014e02768282049601000001')
< false
But here it returns true
> isNaN('014e0276861d077601000001')
< true
What is the difference between these two strings with hex-numbers?
What is reliable way in JS to detect numbers and non-numbers?
Thanks!
Those two strings are not interpreted as hex numbers. Hex numbers must start with 0x.
But the first one has the form of a valid number literal:
2e3
is the same as
2 * Math.pow(10,3);
The second one is invalid because it contains d.
014e02768282049601000001 is a valid number written in an exponential form, like: 5e2 (==500 = 5 * 10²). The second one contains a letter d, which has no particular meaning, thus is not a number.
You can declare the exponential form in JavaScript and many other languages literally:
var b = 3e-20;
The characters e, -, + and . belong to the set of characters used when defining numbers (of course, if used properly). Other characters don't.

javascript comparison of strings

I have the following script
document.write("12" < "2");
which returns true. Any reason why? The documentation says that javascript compares strings numerically but, I don't see how "12" is less than "2".
JavaScript compares strings character by character until one of the characters is different.
1 is less than 2 so it stops comparing after the first character.
I believe it is doing a lexicographic comparison - the first char in string one is '1', which is less than the first char of string two, which is '2'. More about Lexicographic order here: http://en.wikipedia.org/wiki/Lexicographical_order
This is because the first character of "12" is 1, which comes before "2"; and JavaScript string comparison is lexically/alphabetically, rather than numerically. Though it appears partially numeric, since 1 is sorted ahead of 2.
You can, however, simply compare the numbers as numbers:
document.write(parseFloat("12") < parseFloat("2"));
Try:
document.write(parseInt("12") < parseInt("2"));

how exactly do Javascript numeric comparison operators handle strings?

var i = ['5000','35000'];
alert((i[0] < i[1])?'well duh!':'fuzzy math?');
alert((Number(i[0]) < Number(i[1]))?'well duh!':'fuzzy math?');
What's happening here? In the first alert, the text string "5000" evaluates as not less than "35000". I assumed Javascript used Number() when numerically comparing strings, but apparently that's not the case. Just curious how exactly Javascript handles numerically comparing the strings of numbers by default.
Javascript compares strings by character value, whether the strings look like numbers or not.
You can see this in the spec, section 11.8.5, point 4.
'a' < 'b' and 'ab' < 'ac are both true.

Categories