I wrote a Javascript app that I didn't think any modern browser would have any issue with, but when I tested it, it worked fine with Chrome, Safari, Opera, even IE… but not Firefox.
This is the sort in question:
var sorted = Object.keys(teams).sort(function(a, b) {
return -(teams[a][sortBy] < teams[b][sortBy])
});
Here's a JSfiddle I made to demonstrate - http://jsfiddle.net/Aq6sc/1/
What that fiddle should do, is when you click on one of the categories, it should show you 3 "columns". The team name, the category name, and the category value. They should print sorted by category value ascending. And it does in every browser except Firefox.
Your comparison function should return a negative number if the left operand comes before the right one in the sort order, a positive number if the right operand comes first, and 0 if they are equal. Your function only returns -1 or 0. Use this:
var sorted = Object.keys(teams).sort(function(a, b) {
var l = teams[a][sortBy], r = teams[b][sortBy];
return (l < r) ? -1 : ((l > r) ? 1 : 0);
});
http://jsfiddle.net/Aq6sc/4/
Here's a version that behaves exactly the same but might be considered a little more readable:
var sorted = Object.keys(teams).sort(function(a, b) {
var l = teams[a][sortBy], r = teams[b][sortBy];
if (l < r) { return -1; }
if (l > r) { return 1; }
return 0;
});
The problem is that in the sort compare function, you are using a - to reverse the result. If you use !, it should work fine.
var sorted = Object.keys(teams).sort(function(a, b) {
return !(teams[a][sortBy] < teams[b][sortBy])
});
Or you can remove the not and just reverse the comparision
return (teams[a][sortBy] > teams[b][sortBy])
Related
I'm making the Freecodecamp certifications, and there's one problem I cannot see a solution to: the task is to calculate the Least Common Multiple (LCM) for an array of integers (that also means a RANGE of integers, between a min and a max value).
The snippet below gives the correct answer here on SO, on Codepen.io, on my local environment. But not on freecodecamp.org.
function smallestCommons(arr) {
// sorting and cloning the array
const fullArr = createArray(arr.sort((a, b) => a - b))
// calculating the theoretical limit of the size of the LCM
const limit = fullArr.reduce((a, c) => a * c, 1)
// setting the number to start the iteration with
let i = fullArr[0]
// iteration to get the LCM
for (i; i <= limit; i++) {
// if every number in the fullArr divide
// the number being tested (i), then it's the LCM
if (fullArr.every(e => !(i % e))) {
// stop the for loop
break
}
}
// return LCM
return i;
}
// utility function to create the fullArr const in the
// main function
function createArray([a, b]) {
const r = []
for (let i = b; i >= a; i--) {
r.push(i)
}
return r
}
// displaying the results
console.log(smallestCommons([23, 18]));
The error what I see:
the code works correctly with 4 other arrays on freecodecamp.org
the code gives false results - or no results at all for the array [23, 18]. If I get a result, it's not consistent (like 1,000,000 once, then 3,654,236 - I made these numbers up, but the behavior is like that). The result of the [23, 18] input should be 6,056,820 (and it's that here on SO, but not on freecodecamp.org)
As this code is far from optimal I have a feeling that the code execution just runs out of resources at one point, but I get no error for that.
I read the hints on the page (yes, I tried the solutions, and they do work), but I'd like to submit my own code: I know my algorithm is (theoretically) good (although not optimal), but I'd like to make it work in practice too.
I also see that this question had caused problems to others (it's been asked on SO), but I don't feel it's a duplicate.
Does anyone have any ideas?
As it turned out it was a resource problem - the algorithm in my question was correct theoretically but wasn't optimal or effective.
Here's one that is more efficient in solving this problem:
// main function
function smallestCommons(arr) {
const fullArr = createArray(arr.sort((a, b) => a - b))
return findLcm(fullArr, fullArr.length);
}
// creating the range of numbers based on a min and a max value
function createArray([a, b]) {
const r = []
for (let i = b; i >= a; i--) {
r.push(i)
}
return r
}
// smallest common multiple of n numbers
function findLcm(arr, n) {
let ans = arr[0];
for (let i = 1; i < n; i++) {
ans = (((arr[i] * ans)) /
(gcd(arr[i], ans)));
}
return ans;
}
// greatest common divisor
function gcd(a, b) {
if (b == 0) return a;
return gcd(b, a % b);
}
console.log(smallestCommons([1, 5]));
console.log(smallestCommons([5, 1]));
console.log(smallestCommons([2, 10]));
console.log(smallestCommons([23, 18]));
This method was OK on the testing sandbox environment.
I know that the ECMA Script specification does not specify which algorithm to use for sorting arrays, nor does it specify whether the sort should be stable.
I've found this information for Firefox which specifies that firefox uses a stable sort.
Does anyone know about IE 6/7/8, Chrome and Safari?
As of ES2019, sort is required to be stable. In ECMAScript 1st edition through ES2018, it was allowed to be unstable.
Simple test case (ignore the heading, second set of numbers should be sequential if the engine's sort is stable). Note: This test case doesn't work for some versions of Chrome (technically, of V8) that switched sorting algorithms based on the size of the array, using a stable sort for small arrays but an unstable one for larger arrays. (Details.) See the end of the question for a modified version that makes the array large enough to trigger the behavior.
IE's sort has been stable as long as I've ever used it (so IE6). Checking again in IE8 and it appears to still be the case.
And although that Mozilla page you link to says Firefox's sort is stable, I definitely say this was not always the case prior to (and including) Firefox 2.0.
Some cursory results:
IE6+: stable
Firefox < 3: unstable
Firefox >= 3: stable
Chrome < 70: unstable
Chrome >= 70: stable
Opera < 10: unstable
Opera >= 10: stable
Safari 4: stable
Edge: unstable for long arrays (>512 elements)
All tests on Windows.
See also: Fast stable sorting algorithm implementation in javascript
This test case (modified from here) will demonstrate the problem in V8 (for instance, Node v6, Chrome < v70) by ensuring the array has enough entries to pick the "more efficient" sort method; this is written with very old JavaScript engines in mind, so without modern features:
function Pair(_x, _y) {
this.x = _x;
this.y = _y;
}
function pairSort(a, b) {
return a.x - b.x;
}
var y = 0;
var check = [];
while (check.length < 100) {
check.push(new Pair(Math.floor(Math.random() * 3) + 1, ++y));
}
check.sort(pairSort);
var min = {};
var issues = 0;
for (var i = 0; i < check.length; ++i) {
var entry = check[i];
var found = min[entry.x];
if (found) {
if (found.y > entry.y) {
console.log("Unstable at " + found.i + ": " + found.y + " > " + entry.y);
++issues;
}
} else {
min[entry.x] = {x: entry.x, y: entry.y, i: i};
}
}
if (!issues) {
console.log("Sort appears to be stable");
}
I'd like to share a trick I routinely use in C/C++ for qsort().
JS' sort() allows to specify a compare function. Create second array of the same length and fill it with increasing numbers from 0.
function stableSorted(array, compareFunction) {
compareFunction = compareFunction || defaultCompare;
var indicies = new Array(array.length);
for (var i = 0; i < indicies.length; i++)
indicies[i] = i;
This are indexes into the original array. We are going to sort the second array. Make a custom compare function.
indicies.sort(function(a, b)) {
It will get the two elements from the second array: use them as indexes into the original arrays and compare the elements.
var aValue = array[a], bValue = array[b];
var order = compareFunction(a, b);
if (order != 0)
return order;
If elements happen to be equal, then compare their indexes to make the order stable.
if (a < b)
return -1;
else
return 1;
});
After the sort(), the second array would contain indexes which you can use to access the elements of original array in stable sorted order.
var sorted = new Array(array.length);
for (var i = 0; i < sorted.length; i++)
sorted[i] = array[indicies[i]];
return sorted;
}
// The default comparison logic used by Array.sort(), if compareFunction is not provided:
function defaultCompare(a, b) {
a = String(a);
b = String(b);
if (a < b) return -1;
else if (a > b) return 1;
else return 0;
}
In general, stable sort algorithms are only maturing and still require more extra memory compared to the good ol' qsort. I guess that's why very few specs mandate stable sort.
As of V8 v7.0 and Chrome 70, our Array.prototype.sort implementation is now stable. 🎉
Previously, V8 used an unstable QuickSort for arrays with more than 10 elements. Now, V8 uses the stable TimSort algorithm.
The only major engine JavaScript engine that still has an unstable Array#sort implementation is Chakra, as used in Microsoft Edge. Chakra uses QuickSort for arrays with more than 512 elements. For smaller arrays, it uses a stable insertion sort implementation.
Demo: https://mathiasbynens.be/demo/sort-stability
In case anyone finds it useful, I had a polyfill for this that I am now removing:
const stable = (count => {
const
array = new Array(count),
buckets = {};
let i, k, v;
for (i = 0; i < count; ++i) {
array[i] = [Math.floor(Math.random() * 3) + 1, i + 1]; // [1..3, 1..count]
}
array.sort((a, b) => a[0] - b[0]);
for (i = 0; i < count; ++i) {
[k, v] = array[i];
if (buckets[k] > v) {
return false;
}
buckets[k] = v;
}
return true;
// Edge's JS engine has a threshold of 512 before it goes unstable, so use a number beyond that:
})(600);
if (!stable) {
const
{ prototype } = Array,
{ sort } = prototype;
Object.defineProperty(prototype, 'sort', {
configurable : true,
value(sortFn) {
const
array = this,
len = array.length,
temp = new Array(len);
let i;
for (i = len; i-- > 0; /* empty */) {
temp[i] = i;
}
sortFn = sortFn || defaultSort;
sort.call(temp, (index1, index2) => sortFn(array[index1], array[index2]) || index1 - index2);
// we cannot do this directly into array since we may overwrite an element before putting it into the
// correct spot:
for (i = len; i-- > 0; /* empty */) {
temp[i] = array[temp[i]];
}
for (i = len; i-- > 0; /* empty */) {
array[i] = temp[i];
}
return array;
}
});
}
If you are looking for a list of browsers where you should utilize a non native sorting algorithm, my suggestion is don't.
Instead do a sort sanity check when the script loads and make your decision from that.
As the spec doesn't require a particular behavior in that regard, it is not immune to later change, even within the same browser line.
You could submit a patch to http://www.browserscope.org/ to include such tests in their suite. But again, feature detection is superior to browser detection.
I know that the ECMA Script specification does not specify which algorithm to use for sorting arrays, nor does it specify whether the sort should be stable.
I've found this information for Firefox which specifies that firefox uses a stable sort.
Does anyone know about IE 6/7/8, Chrome and Safari?
As of ES2019, sort is required to be stable. In ECMAScript 1st edition through ES2018, it was allowed to be unstable.
Simple test case (ignore the heading, second set of numbers should be sequential if the engine's sort is stable). Note: This test case doesn't work for some versions of Chrome (technically, of V8) that switched sorting algorithms based on the size of the array, using a stable sort for small arrays but an unstable one for larger arrays. (Details.) See the end of the question for a modified version that makes the array large enough to trigger the behavior.
IE's sort has been stable as long as I've ever used it (so IE6). Checking again in IE8 and it appears to still be the case.
And although that Mozilla page you link to says Firefox's sort is stable, I definitely say this was not always the case prior to (and including) Firefox 2.0.
Some cursory results:
IE6+: stable
Firefox < 3: unstable
Firefox >= 3: stable
Chrome < 70: unstable
Chrome >= 70: stable
Opera < 10: unstable
Opera >= 10: stable
Safari 4: stable
Edge: unstable for long arrays (>512 elements)
All tests on Windows.
See also: Fast stable sorting algorithm implementation in javascript
This test case (modified from here) will demonstrate the problem in V8 (for instance, Node v6, Chrome < v70) by ensuring the array has enough entries to pick the "more efficient" sort method; this is written with very old JavaScript engines in mind, so without modern features:
function Pair(_x, _y) {
this.x = _x;
this.y = _y;
}
function pairSort(a, b) {
return a.x - b.x;
}
var y = 0;
var check = [];
while (check.length < 100) {
check.push(new Pair(Math.floor(Math.random() * 3) + 1, ++y));
}
check.sort(pairSort);
var min = {};
var issues = 0;
for (var i = 0; i < check.length; ++i) {
var entry = check[i];
var found = min[entry.x];
if (found) {
if (found.y > entry.y) {
console.log("Unstable at " + found.i + ": " + found.y + " > " + entry.y);
++issues;
}
} else {
min[entry.x] = {x: entry.x, y: entry.y, i: i};
}
}
if (!issues) {
console.log("Sort appears to be stable");
}
I'd like to share a trick I routinely use in C/C++ for qsort().
JS' sort() allows to specify a compare function. Create second array of the same length and fill it with increasing numbers from 0.
function stableSorted(array, compareFunction) {
compareFunction = compareFunction || defaultCompare;
var indicies = new Array(array.length);
for (var i = 0; i < indicies.length; i++)
indicies[i] = i;
This are indexes into the original array. We are going to sort the second array. Make a custom compare function.
indicies.sort(function(a, b)) {
It will get the two elements from the second array: use them as indexes into the original arrays and compare the elements.
var aValue = array[a], bValue = array[b];
var order = compareFunction(a, b);
if (order != 0)
return order;
If elements happen to be equal, then compare their indexes to make the order stable.
if (a < b)
return -1;
else
return 1;
});
After the sort(), the second array would contain indexes which you can use to access the elements of original array in stable sorted order.
var sorted = new Array(array.length);
for (var i = 0; i < sorted.length; i++)
sorted[i] = array[indicies[i]];
return sorted;
}
// The default comparison logic used by Array.sort(), if compareFunction is not provided:
function defaultCompare(a, b) {
a = String(a);
b = String(b);
if (a < b) return -1;
else if (a > b) return 1;
else return 0;
}
In general, stable sort algorithms are only maturing and still require more extra memory compared to the good ol' qsort. I guess that's why very few specs mandate stable sort.
As of V8 v7.0 and Chrome 70, our Array.prototype.sort implementation is now stable. 🎉
Previously, V8 used an unstable QuickSort for arrays with more than 10 elements. Now, V8 uses the stable TimSort algorithm.
The only major engine JavaScript engine that still has an unstable Array#sort implementation is Chakra, as used in Microsoft Edge. Chakra uses QuickSort for arrays with more than 512 elements. For smaller arrays, it uses a stable insertion sort implementation.
Demo: https://mathiasbynens.be/demo/sort-stability
In case anyone finds it useful, I had a polyfill for this that I am now removing:
const stable = (count => {
const
array = new Array(count),
buckets = {};
let i, k, v;
for (i = 0; i < count; ++i) {
array[i] = [Math.floor(Math.random() * 3) + 1, i + 1]; // [1..3, 1..count]
}
array.sort((a, b) => a[0] - b[0]);
for (i = 0; i < count; ++i) {
[k, v] = array[i];
if (buckets[k] > v) {
return false;
}
buckets[k] = v;
}
return true;
// Edge's JS engine has a threshold of 512 before it goes unstable, so use a number beyond that:
})(600);
if (!stable) {
const
{ prototype } = Array,
{ sort } = prototype;
Object.defineProperty(prototype, 'sort', {
configurable : true,
value(sortFn) {
const
array = this,
len = array.length,
temp = new Array(len);
let i;
for (i = len; i-- > 0; /* empty */) {
temp[i] = i;
}
sortFn = sortFn || defaultSort;
sort.call(temp, (index1, index2) => sortFn(array[index1], array[index2]) || index1 - index2);
// we cannot do this directly into array since we may overwrite an element before putting it into the
// correct spot:
for (i = len; i-- > 0; /* empty */) {
temp[i] = array[temp[i]];
}
for (i = len; i-- > 0; /* empty */) {
array[i] = temp[i];
}
return array;
}
});
}
If you are looking for a list of browsers where you should utilize a non native sorting algorithm, my suggestion is don't.
Instead do a sort sanity check when the script loads and make your decision from that.
As the spec doesn't require a particular behavior in that regard, it is not immune to later change, even within the same browser line.
You could submit a patch to http://www.browserscope.org/ to include such tests in their suite. But again, feature detection is superior to browser detection.
I know that the ECMA Script specification does not specify which algorithm to use for sorting arrays, nor does it specify whether the sort should be stable.
I've found this information for Firefox which specifies that firefox uses a stable sort.
Does anyone know about IE 6/7/8, Chrome and Safari?
As of ES2019, sort is required to be stable. In ECMAScript 1st edition through ES2018, it was allowed to be unstable.
Simple test case (ignore the heading, second set of numbers should be sequential if the engine's sort is stable). Note: This test case doesn't work for some versions of Chrome (technically, of V8) that switched sorting algorithms based on the size of the array, using a stable sort for small arrays but an unstable one for larger arrays. (Details.) See the end of the question for a modified version that makes the array large enough to trigger the behavior.
IE's sort has been stable as long as I've ever used it (so IE6). Checking again in IE8 and it appears to still be the case.
And although that Mozilla page you link to says Firefox's sort is stable, I definitely say this was not always the case prior to (and including) Firefox 2.0.
Some cursory results:
IE6+: stable
Firefox < 3: unstable
Firefox >= 3: stable
Chrome < 70: unstable
Chrome >= 70: stable
Opera < 10: unstable
Opera >= 10: stable
Safari 4: stable
Edge: unstable for long arrays (>512 elements)
All tests on Windows.
See also: Fast stable sorting algorithm implementation in javascript
This test case (modified from here) will demonstrate the problem in V8 (for instance, Node v6, Chrome < v70) by ensuring the array has enough entries to pick the "more efficient" sort method; this is written with very old JavaScript engines in mind, so without modern features:
function Pair(_x, _y) {
this.x = _x;
this.y = _y;
}
function pairSort(a, b) {
return a.x - b.x;
}
var y = 0;
var check = [];
while (check.length < 100) {
check.push(new Pair(Math.floor(Math.random() * 3) + 1, ++y));
}
check.sort(pairSort);
var min = {};
var issues = 0;
for (var i = 0; i < check.length; ++i) {
var entry = check[i];
var found = min[entry.x];
if (found) {
if (found.y > entry.y) {
console.log("Unstable at " + found.i + ": " + found.y + " > " + entry.y);
++issues;
}
} else {
min[entry.x] = {x: entry.x, y: entry.y, i: i};
}
}
if (!issues) {
console.log("Sort appears to be stable");
}
I'd like to share a trick I routinely use in C/C++ for qsort().
JS' sort() allows to specify a compare function. Create second array of the same length and fill it with increasing numbers from 0.
function stableSorted(array, compareFunction) {
compareFunction = compareFunction || defaultCompare;
var indicies = new Array(array.length);
for (var i = 0; i < indicies.length; i++)
indicies[i] = i;
This are indexes into the original array. We are going to sort the second array. Make a custom compare function.
indicies.sort(function(a, b)) {
It will get the two elements from the second array: use them as indexes into the original arrays and compare the elements.
var aValue = array[a], bValue = array[b];
var order = compareFunction(a, b);
if (order != 0)
return order;
If elements happen to be equal, then compare their indexes to make the order stable.
if (a < b)
return -1;
else
return 1;
});
After the sort(), the second array would contain indexes which you can use to access the elements of original array in stable sorted order.
var sorted = new Array(array.length);
for (var i = 0; i < sorted.length; i++)
sorted[i] = array[indicies[i]];
return sorted;
}
// The default comparison logic used by Array.sort(), if compareFunction is not provided:
function defaultCompare(a, b) {
a = String(a);
b = String(b);
if (a < b) return -1;
else if (a > b) return 1;
else return 0;
}
In general, stable sort algorithms are only maturing and still require more extra memory compared to the good ol' qsort. I guess that's why very few specs mandate stable sort.
As of V8 v7.0 and Chrome 70, our Array.prototype.sort implementation is now stable. 🎉
Previously, V8 used an unstable QuickSort for arrays with more than 10 elements. Now, V8 uses the stable TimSort algorithm.
The only major engine JavaScript engine that still has an unstable Array#sort implementation is Chakra, as used in Microsoft Edge. Chakra uses QuickSort for arrays with more than 512 elements. For smaller arrays, it uses a stable insertion sort implementation.
Demo: https://mathiasbynens.be/demo/sort-stability
In case anyone finds it useful, I had a polyfill for this that I am now removing:
const stable = (count => {
const
array = new Array(count),
buckets = {};
let i, k, v;
for (i = 0; i < count; ++i) {
array[i] = [Math.floor(Math.random() * 3) + 1, i + 1]; // [1..3, 1..count]
}
array.sort((a, b) => a[0] - b[0]);
for (i = 0; i < count; ++i) {
[k, v] = array[i];
if (buckets[k] > v) {
return false;
}
buckets[k] = v;
}
return true;
// Edge's JS engine has a threshold of 512 before it goes unstable, so use a number beyond that:
})(600);
if (!stable) {
const
{ prototype } = Array,
{ sort } = prototype;
Object.defineProperty(prototype, 'sort', {
configurable : true,
value(sortFn) {
const
array = this,
len = array.length,
temp = new Array(len);
let i;
for (i = len; i-- > 0; /* empty */) {
temp[i] = i;
}
sortFn = sortFn || defaultSort;
sort.call(temp, (index1, index2) => sortFn(array[index1], array[index2]) || index1 - index2);
// we cannot do this directly into array since we may overwrite an element before putting it into the
// correct spot:
for (i = len; i-- > 0; /* empty */) {
temp[i] = array[temp[i]];
}
for (i = len; i-- > 0; /* empty */) {
array[i] = temp[i];
}
return array;
}
});
}
If you are looking for a list of browsers where you should utilize a non native sorting algorithm, my suggestion is don't.
Instead do a sort sanity check when the script loads and make your decision from that.
As the spec doesn't require a particular behavior in that regard, it is not immune to later change, even within the same browser line.
You could submit a patch to http://www.browserscope.org/ to include such tests in their suite. But again, feature detection is superior to browser detection.
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