Related
How can i combine the arrays?
[
['1','1','1','2','1'],
['3','3','4','4','4'],
['6','6','7','8','7'],
]
with those arrays there are many combinations, some of the are these:
1,3,6
1,3,6 -> this not, because its duplicate
1,4,7
2,4,8
1,4,7 -> this not, because its duplicate
how can we replace the wrong combination? one solution will be:
1,3,6
1,3,7 -> fixed
1,4,6
1,4,8
2,4,7 -> fixed
rules:
in the first column, 1 should appear 4 times
in the first column, 2 should appear 1 times
in the second column, 3 should appear 2 times
in the second column, 4 should appear 3 times
in the third column, 6 should appear 2 times
in the third column, 7 should appear 2 times
in the third column, 8 should appear 1 times
my attempt is: i would like to generate many combinations, but its not safe the number of appears
function available(array) {
let currentIndex = array.length,
randomIndex;
while (currentIndex != 0) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--;
[array[currentIndex], array[randomIndex]] = [
array[randomIndex], array[currentIndex]
];
}
return array;
}
const arrays = [
['1', '1', '1', '2', '1'],
['3', '3', '4', '4', '4'],
['6', '6', '7', '8', '7'],
]
for (const current of arrays) {
console.log(available(current))
}
Ignore that the individual strings contain digits. This doesn't matter. At that level, all that matters is that they're strings. (We wouldn't care about that either, just that they're some kind of comparable symbol, but we can take advantage of the fact that they're stings in validation.)
Integers, in general, don't have to have any particular representation. Just because, say, 3 is shaped like that doesn't say anything about the concept of 3. It could be represented in any way so long as it's unique relative to others of its type. For example, we could represent it as [1,1,1].
For each row, we need to iterate through the permutations of that row. Heap's Algorithm allows us to do that in a predictable way without breaking the rules for how many of each kind of item goes in each row.
If we think of that iteration as a kind of counting (the first permutation is 1, the next is 2, etc.), we can count through the permutations of each row as though they were digits in a strange kind of integer. In this way, we can iterate over all combinations of the permutations of the rows.
All that's left is validating each result against duplicate columns. We do this by joining along columns, and adding the results to a set. So long as the set ends up with the same length as the rows, we know there were no duplicates.
solve() only returns the first solution encountered, if any. However, it would be pretty simple to adjust it to return all solutions.
We use .every as a kind of .forEach with the additional ability to end the loop early and to signal whether or not that happened.
function* is known as a generator function. They return a generator object, a thing that wraps the function and lets you return values (via yield) and then later come back and resume the function from that point.
// Heap's Algorithm modified to skip swaps of the same value
// Allows us to iterate over permutations of a row
function* iterHeapsAlgo(arr) {
const A = Array.from(arr); // shallow copy
const len = A.length;
const c = new Array(len).fill(0);
let i = 0;
yield A;
while(i < len) {
if(c[i] < i) {
let j = i&1 ? c[i] : 0;
if(A[i] != A[j]) {
[A[j], A[i]] = [A[i], A[j]];
yield A;
}
c[i]++;
i = 0;
} else {
c[i] = 0;
i++;
}
}
};
// Iterate over all combinations of all rows
// Typical counting algorithm with shortcut to take advantage of exposed state
function* iterCount(data) {
const state = data.map(v => iterHeapsAlgo(v));
const current = state.map(v => v.next().value);
yield current;
while(true) {
const isEnd = state.every((v,i) => {
let n = v.next();
if(n.done) {
state[i] = iterHeapsAlgo(data[i]);
current[i] = state[i].next().value;
return true;
}
});
if(isEnd) return;
yield current;
}
}
const validate = data => {
const set = new Set();
return data[0].every((_,i) => {
set.add(data.reduce((s,v) => `${s}\uffff${v[i]}`, ''));
return set.size-1 == i;
});
};
const solve = start => {
for(const current of iterCount(start)) {
if(validate(current)) {
return current.map(v => Array.from(v)); // depth 2 copy
}
}
return null;
};
console.log(solve([
['1','1','1','2','1'],
['3','3','4','4','4'],
['6','6','7','8','7'],
]) || 'No solution found');
.as-console-wrapper { top: 0; max-height: 100% !important; }
EDIT: Adjustments based on comments. Thanks #Mulan and #ScottSauyet
Maybe I'm missing something, but it seems like you're looking for the product of the arrays with only unique combinations of elements -
const unique = a =>
Array.from(new Set(a))
const product = t =>
t.length == 0
? [[]]
: product(t.slice(1)).flatMap(p => unique(t[0]).map(v => [v, ...p]))
const myinput = [
['1','1','1','2','1'],
['3','3','4','4','4'],
['6','6','7','8','7'],
]
for (const combination of product(myinput))
console.log(String(combination))
1,3,6
2,3,6
1,4,6
2,4,6
1,3,7
2,3,7
1,4,7
2,4,7
1,3,8
2,3,8
1,4,8
2,4,8
By inverting the loops, we can generate the unique products in lexicographical order -
const bind = (f, x) => f(x)
const unique = a =>
Array.from(new Set(a))
const product = t =>
t.length == 0
? [[]]
: bind
( r => unique(t[0]).flatMap(v => r.map(p => [v, ...p]))
, product(t.slice(1))
)
const myinput = [
['1','1','1','2','1'],
['3','3','4','4','4'],
['6','6','7','8','7'],
]
for (const combination of product(myinput))
console.log(String(combination))
1,3,6
1,3,7
1,3,8
1,4,6
1,4,7
1,4,8
2,3,6
2,3,7
2,3,8
2,4,6
2,4,7
2,4,8
Finally we can generate the products lazily by using a generator -
const unique = a =>
Array.from(new Set(a))
function* product(t) {
if (t.length == 0)
yield []
else
for (const p of product(t.slice(1)))
for (const v of unique(t[0]))
yield [v, ...p]
}
const myinput = [
['1','1','1','2','1'],
['3','3','4','4','4'],
['6','6','7','8','7'],
]
for (const combination of product(myinput))
console.log(String(combination))
1,3,6
2,3,6
1,4,6
2,4,6
1,3,7
2,3,7
1,4,7
2,4,7
1,3,8
2,3,8
1,4,8
2,4,8
If you are looking for permutations, see this related Q&A.
I am trying to write a JavaScript function that returns all combinations of the elements of an array of unknown length. The argument to be passed to the function should be an array of single digit strings e.g. [ "5", "7", "9" ].
An example to illustrate the desired functionality:
If you pass in an array of [ "5", "7", "9" ], it should return an array with all the possible 3-digit combinations of those 3 numbers i.e. [ "579", "759", "957", "795",…].
If you passed in an array of [ "2", "5", "4", "6" ], you would get the 4-digit combinations of those 4 numbers, i.e. [ "2546", "2654", "2465",…].
If you passed in an array of length 5, you would get the 5-digit combinations of those 5 numbers, and so on.
If the inputted array has the same digit multiple times, that number should appear multiple times in the resulting array e.g. an input of [ "5", "5", "6" ] produces an output of [ "556", "655", "565",…].
I have looked around and it seems that recursion might be the way to go, but I am struggling to get it working. I have attempted the below solution which currently works for 3-digit numbers but I can’t figure out how to make a function which works with an array of unknown length.
function getDoubleDigitCombinations(input) {
let result = [];
const first = input[0];
const last = input[1];
result.push(first + last);
result.push(last + first);
return result;
}
function getTripleDigitCombinations(input) {
let result = [];
let main; // This is the number in question.
let other1; // These are the other numbers.
let other2;
for (i = 0; i < input.length; i++) {
let arr = input.slice(); // Make a copy of the input array.
main = input[i];
arr.splice(i, 1); // Remove the main element from the array …
other1 = arr[0]; // … so that you are left with the other two numbers.
other2 = arr[1];
console.log(`Main is ${main}`);
console.log(`other1 is ${other1} and other2 is ${other2}`);
const arr2 = getDoubleDigitCombinations([other1, other2]); // Get the combinations of the others.
result.push(main + arr2[0]); // Concatenate main with both of the others combinations.
result.push(main + arr2[1]);
}
return result;
}
let result2 = getTripleDigitCombinations([ "6", "7", "8" ]);
console.log("result2 is ...");
for (i = 0; i < result2.length; i++) {
console.log(result2[i]);
}
Heap's algorithm is still, I believe, the gold standard for efficiency. Victor's answer covers that well.
But since any algorithm has to be at least O(n!), we're never going to get stunning performance in generating permutations. We might want to look also at simplicity.
Another implementation is decidedly simpler:
const excluding = (i) => (xs) =>
[... xs .slice (0, i), ... xs .slice (i + 1)]
const permutations = (xs) =>
xs .length == 0
? [[]]
: xs .flatMap ((x, i) => permutations (excluding (i) (xs)) .map (p => x + p))
console .log (permutations (['5', '6', '7']))
Here we use a small helper function, excluding, which returns a copy of an array removing the value at a given index. Then permutations loops over the values in the array, taking each in turn to be the first value of a set of permutations, and finding the remainder of those permutations by recurring on the array found by excluding the current index.
This has the nice feature that the permutations are returned in an obvious order. If the original array is sorted, say ['a', 'b', 'c'], then the results are returned in alphabetic order: ['abc', 'acb', 'bac', 'bca', 'cab', 'cba']. This is not usually essential, but it can be useful.
Note that this solution is more commonly written with this line:
: xs .flatMap ((x, i) => permutations (excluding (i) (xs)) .map (p => [x, ... p]))
which returns an array of arrays ([['5', '6', '7'], ['5', '7', '6'], ...]) instead of an array of strings (['567', '576', ...]).
There is another version which I've seen recently that is even simpler. It's not original, but I don't recall where I saw it -- probably here on StackOverflow. This is my own implementation of that idea, but I think it's pretty close to the original:
const rotations = ([l, ...ls], rs = []) =>
l == undefined ? [] : [[l, ...ls, ...rs], ... rotations (ls, [...rs, l])]
const permutations = ([l, ...ls]) =>
l == undefined ? [[]] : [...permutations (ls) .flatMap (p => rotations ([l, ...p])) ]
console .log (permutations (['5', '6', '7']) .map (p => p .join ('')))
.as-console-wrapper {max-height: 100% !important; top: 0}
Here we use a function rotations which takes an array and returns all the wrapped-around rotations of that array. For example:
rotations(['x', 'y', 'z'])
//=> [['x', 'y', 'z'], ['y', 'z', 'x'], ['z', 'x', 'y']]
We use that to write permutations by taking out the first element, recursively finding the permutations of the remaining elements, and for each, sticking the first element back on and returning all the rotations.
This is short and quite clever. I would probably stick to either Heap's algorithm for speed or to the one above for the nicely ordered output. But this one is still worth considering for the simplicity.
While this algorithm could be fixed up to return strings, it would be more intrusive than it was in the previous version, involving changes to both rotations and permutations, and I would prefer to stick to generating the strings on the output of it as done above with .map (p => p .join ('')). If you wanted to do it, though, it might look like this:
const rotations = ([l, ...ls], rs = '') =>
l == undefined ? [] : [l + ls.join('') + rs, ... rotations (ls, rs + l)]
const permutations = ([l, ...ls]) =>
l == undefined ? [[]] : [...permutations (ls) .flatMap (p => rotations (l + p)) ]
permutations (['5', '7', '7']) //=> ['577', '775', '757', '577', '775', '757']
A fun problem! I wanted to implement using generators. This allows you to work with the permutations one-by-one as they are generated, rather than having to compute all permutations before the entire answer is provided -
const input =
["🔴","🟢","🔵","🟡"]
for (const p of permutations(input))
console.log(p.join(""))
🔴🟢🔵🟡
🟢🔴🔵🟡
🟢🔵🔴🟡
🟢🔵🟡🔴
🔴🔵🟢🟡
🔵🔴🟢🟡
🔵🟢🔴🟡
🔵🟢🟡🔴
🔴🔵🟡🟢
🔵🔴🟡🟢
🔵🟡🔴🟢
🔵🟡🟢🔴
🔴🟢🟡🔵
🟢🔴🟡🔵
🟢🟡🔴🔵
🟢🟡🔵🔴
🔴🟡🟢🔵
🟡🔴🟢🔵
🟡🟢🔴🔵
🟡🟢🔵🔴
🔴🟡🔵🟢
🟡🔴🔵🟢
🟡🔵🔴🟢
🟡🔵🟢🔴
This allows us to do cool things like, finding specific patterns -
// find all permutations where red is left of green
for (const p of permutations(input))
if (p.indexOf("🔴") < p.indexOf("🟢"))
console.log(p.join(""))
🟡🔵🔴🟢
🔵🟡🔴🟢
🔵🔴🟢🟡
🔵🔴🟡🟢
🟡🔴🟢🔵
🟡🔴🔵🟢
🔴🟢🟡🔵
🔴🟡🟢🔵
🔴🟡🔵🟢
🔴🟢🔵🟡
🔴🔵🟢🟡
🔴🔵🟡🟢
// find all permutations where blue and yellow are adjacent
for (const p of permutations(input))
if (Math.abs(p.indexOf("🔵") - p.indexOf("🟡")) == 1)
console.log(p.join(""))
🟢🟡🔵🔴
🟡🔵🟢🔴
🟡🔵🔴🟢
🟢🔵🟡🔴
🔵🟡🟢🔴
🔵🟡🔴🟢
🟢🔴🟡🔵
🔴🟢🟡🔵
🔴🟡🔵🟢
🟢🔴🔵🟡
🔴🟢🔵🟡
🔴🔵🟡🟢
And if we wanted to find the only the first permutation where such a condition is true, we can use return or break to stop the generator and no more permutations will be computed.
We just have to implement permutations -
function* permutations (t)
{ if (t.length < 2)
yield t
else
for (const p of permutations(t.slice(1)))
for (const r of rotations(p, t[0]))
yield r
}
Which depends on rotations -
function* rotations (t, v)
{ if (t.length == 0)
yield [v]
else
yield *chain
( [[v, ...t]]
, map(rotations(t.slice(1), v), r => [t[0], ...r])
)
}
Which depends on two generic functions for working with iterables, map and chain -
function* map (t, f)
{ for (const e of t)
yield f(e)
}
function* chain (...ts)
{ for (const t of ts)
for (const e of t)
yield e
}
Expand the snippet to verify the results in your own browser
function* permutations (t)
{ if (t.length < 2)
yield t
else
for (const p of permutations(t.slice(1)))
for (const r of rotations(p, t[0]))
yield r
}
function* rotations (t, v)
{ if (t.length == 0)
yield [v]
else
yield *chain
( [[v, ...t]]
, map(rotations(t.slice(1), v), r => [t[0], ...r])
)
}
function* map (t, f)
{ for (const e of t)
yield f(e)
}
function* chain (...ts)
{ for (const t of ts)
for (const e of t)
yield e
}
const input =
["🔴","🟢","🔵","🟡"]
console.log("\nred is left of green")
for (const p of permutations(input))
if (p.indexOf("🔴") < p.indexOf("🟢"))
console.log(p.join(""))
console.log("\nblue and yellow are adjacent")
for (const p of permutations(input))
if (Math.abs(p.indexOf("🔵") - p.indexOf("🟡")) == 1)
console.log(p.join(""))
I hope you enjoyed this post as much as I enjoyed writing it :D
To compute combinations using a similar technique, see this related Q&A.
Heap's algorithm can be used to generate all permutations (without repetitions) of array elements, you can then use those permutations with array.join("") to convert them to strings. This works for arrays of any size and any type:
Here is a quick javascript implementation:
// some global variable to store the results
var result = []
// currentSize should be invoked with the array size
function permutation(arr, currentSize) {
if (currentSize == 1) { // recursion base-case (end)
result.push(arr.join(""));
return;
}
for (let i = 0; i < currentSize; i++){
permutation(arr, currentSize - 1);
if (currentSize % 2 == 1) {
let temp = arr[0];
arr[0] = arr[currentSize - 1];
arr[currentSize - 1] = temp;
} else {
let temp = arr[i];
arr[i] = arr[currentSize - 1];
arr[currentSize - 1] = temp;
}
}
}
let array = ["1","2","3","4"];
permutation(array, array.length);
console.log(result);
// use result here
Keep in mind that this is very computationally expensive, with complexity of O(n!).
The following might serve your need after adjusting argument to accept array instead of a number.
function combinator(nbr) {
if (typeof nbr !== 'number' || nbr>999999999) return 'NaN'
const combinedArr = []
const _nbr = `${nbr}`.split('')
combinatorRec(_nbr, [])
function combinatorRec(_nbr, prev){
if (_nbr.length === 0) {
combinedArr.push(parseInt(prev))
return
}
_nbr.forEach((char,i)=>{
const _nbrI = [..._nbr]
_nbrI.splice(i,1)
combinatorRec(_nbrI, prev+char )
})
}
const uniqueArray = combinedArr.filter((item, pos) => (combinedArr.indexOf(item) === pos))
return uniqueArray
}
I desperately need to implement client side sorting that emulates sorting through our tastypie api, which can take multiple fields and return sorted data. So if for example I have data like:
arr = [
{ name: 'Foo LLC', budget: 3500, number_of_reqs: 1040 },
{ name: '22nd Amendment', budget: 1500, number_of_reqs: 2000 },
{ name: 'STS 10', budget: 50000, number_of_reqs: 500 },
...
etc.
]
and given columns to sort e.g.:['name', '-number_of_reqs'] it should sort by name (ascending) and number_of_reqs (descending). I can't get my head around this,
first of all it has to be "natural sort", it supposed to be fairly easy to get if we're talking about sorting a single column, but I need to be able to sort in multiple.
Also I'm not sure why I'm getting different results (from the way how api does it) when using lodash's _.sortBy? Is _.sortBy not "natural" or it's our api broken?
Also I was looking for an elegant solution. Just recently started using Ramdajs, it's so freaking awesome. I bet it would be easier to build sorting I need using that? I've tried, still can't get it right. Little help?
upd:
I found this and using it with Ramda like this:
fn = R.compose(R.sort(naturalSort), R.pluck("name"))
fn(arr)
seems to work for flat array, yet I still need to find a way to apply it for multiple fields in my array
fn = R.compose(R.sort(naturalSort), R.pluck("name"))
seems to be working
Really? I would expect that to return a sorted array of names, not sort an array of objects by their name property.
Using sortBy unfortunately doesn't let us supply a custom comparison function (required for natural sort), and combining multiple columns in a single value that compares consistently might be possible but is cumbersome.
I still don't know how to do it for multiple fields
Functional programming can do a lot here, unfortunately Ramda isn't really equipped with useful functions for comparators (except R.comparator). We need three additional helpers:
on (like the one from Haskell), which takes an a -> b transformation and a b -> b -> Number comparator function to yield a comparator on two as. We can create it with Ramda like this:
var on = R.curry(function(map, cmp) {
return R.useWith(cmp, map, map);
return R.useWith(cmp, [map, map]); // since Ramda >0.18
});
or - just like ||, but on numbers not limited to booleans like R.or. This can be used to chain two comparators together, with the second only being invoked if the first yields 0 (equality). Alternatively, a library like thenBy could be used for this. But let's define it ourselves:
var or = R.curry(function(fst, snd, a, b) {
return fst(a, b) || snd(a, b);
});
negate - a function that inverses a comparison:
function negate(cmp) {
return R.compose(R.multiply(-1), cmp);
}
Now, equipped with these we only need our comparison functions (that natural sort is an adapted version of the one you found, see also Sort Array Elements (string with numbers), natural sort for more):
var NUMBER_GROUPS = /(-?\d*\.?\d+)/g;
function naturalCompare(a, b) {
var aa = String(a).split(NUMBER_GROUPS),
bb = String(b).split(NUMBER_GROUPS),
min = Math.min(aa.length, bb.length);
for (var i = 0; i < min; i++) {
var x = aa[i].toLowerCase(),
y = bb[i].toLowerCase();
if (x < y) return -1;
if (x > y) return 1;
i++;
if (i >= min) break;
var z = parseFloat(aa[i]) - parseFloat(bb[i]);
if (z != 0) return z;
}
return aa.length - bb.length;
}
function stringCompare(a, b) {
a = String(a); b = String(b);
return +(a>b)||-(a<b);
}
function numberCompare(a, b) {
return a-b;
}
And now we can compose exactly the comparison on objects that you want:
fn = R.sort(or(on(R.prop("name"), naturalCompare),
on(R.prop("number_of_reqs"), negate(numberCompare))));
fn(arr)
I think this works.
var arr = [
{ name: 'Foo LLC', budget: 3500, number_of_reqs: 1040 },
{ name: '22nd Amendment', budget: 1500, number_of_reqs: 2000 },
{ name: 'STS 10', budget: 50000, number_of_reqs: 5000 },
{ name: 'STS 10', budget: 50000, number_of_reqs: 500 }
];
var columns = ['name', 'number_of_reqs'];
var NUMBER_GROUPS = /(-?\d*\.?\d+)/g;
var naturalSort = function (a, b, columnname) {
var a_field1 = a[columnname],
b_field1 = b[columnname],
aa = String(a_field1).split(NUMBER_GROUPS),
bb = String(b_field1).split(NUMBER_GROUPS),
min = Math.min(aa.length, bb.length);
for (var i = 0; i < min; i++) {
var x = parseFloat(aa[i]) || aa[i].toLowerCase(),
y = parseFloat(bb[i]) || bb[i].toLowerCase();
if (x < y) return -1;
else if (x > y) return 1;
}
return 0;
};
arr.sort(function(a, b) {
var result;
for (var i = 0; i < columns.length; i++) {
result = naturalSort(a, b, columns[i]);
if (result !== 0) return result; // or -result for decending
}
return 0; //If both are exactly the same
});
console.log(arr);
Bergi's answer is useful and quite interesting, but it changes the API you requested. Here's one that creates the API you were seeking:
var multisort = (function() {
var propLt = R.curry(function(name, a, b) {
return a[name] < b[name];
});
return function(keys, objs) {
if (arguments.length === 0) {throw new TypeError('cannot sort on nothing');}
var fns = R.map(function(key) {
return key.charAt(0) === "-" ?
R.pipe(R.comparator(propLt(R.substringFrom(1, key))), R.multiply(-1)) :
R.comparator(propLt(key));
}, keys);
var sorter = function(a, b) {
return R.reduce(function(acc, fn) {return acc || fn(a, b);}, 0, fns);
}
return arguments.length === 1 ? R.sort(sorter) : R.sort(sorter, objs);
};
}());
multisort(['name', '-number_of_reqs'], arr); //=> sorted clone
It's manually curried rather than calling R.curry because a fair bit of the work is involved in creating the separate sort functions, which could then be reused if you are sorting many lists with the same set of keys. If that's not a concern, this could be simplified a bit.
If you're willing to add another dependency to your project, #panosoft/ramda-utils comes with a compareProps function that does exactly what the original question was asking for.
So, given your original example, to sort descending by budget and then by name, you could do something like this:
var props = ["-budget", "name"];
var comparator = Ru.compareProps(props);
var sortedList = R.sort(comparator, arr);
use the javascript native sort:
Array.prototype.multisort = function(columns) {
var arr = this;
arr.sort(function(a, b) {
return compare(a, b, 0);
});
function compare(a, b, colindex) {
if (colindex >= columns.length) return 0;
var columnname = columns[colindex];
var a_field1 = a[columnname];
var b_field1 = b[columnname];
var asc = (colindex % 2 === 0);
if (a_field1 < b_field1) return asc ? -1 : 1;
else if (a_field1 > b_field1) return asc ? 1 : -1;
else return compare(a, b, colindex + 1);
}
}
var arr = [{ name: 'Foo LLC', budget: 3500, number_of_reqs: 1040 },
{ name: '22nd Amendment',budget: 1500, number_of_reqs: 2000 },
{ name: 'STS 10', budget: 50000,number_of_reqs: 5000 },
{ name: 'STS 10', budget: 50000,number_of_reqs: 500 }];
arr.multisort(['name', 'number_of_reqs']);
if (window.console) window.console.log(arr);
In Javascript, if I have an array of arrays, like the following:
X = [ [1,2,3,4],
[1,1,2,3],
[1,1,3],
[1,4],
[2,1,2],
[2,2]
]
Javascript sorts my array, comparing first entry first, then second, and so on, so that X.sort() returns the following:
[ [1,1,2,3],
[1,1,3],
[1,2,3,4],
[1,4],
[2,1,2],
[2,2]
]
Which is what I want. The problem is that the comparison operator for comparing the elements in the arrays is lexicographical, so [10,2] < [2,2], and, for example,
[[10,2],[1,1,3],[2,2]].sort() -> [[1,1,3],[10,2],[2,2]]
I need it to sort numerically, so that I get a sorted array of [[1,1,3],[2,2],[10,2]].
I tried using a comparison function of function(a,b){return (a-b) }, which would work for sorting an array of numbers, but this fails to properly sort my array, which makes sense (I think) because [10,2] - [1,1,3] yields NaN
How do I go about sorting an array of numeric arrays?
As I said in my comment, the sort function needs to account for the fact that it's receiving arrays as arguments and not plain values. So you need to handle them accordingly.
I suggest this;
var compFunc = function (a, b) {
var len = a.length > b.length ? b.length : a.length;
for(var i=0; i<len; ++i) {
if(a[i] - b[i] !== 0)
return a[i] - b[i];
}
return (a.length - b.length);
};
It first tries to look for differences in the common length of the two arrays. If the common length is exactly the same, then it sorts on the basis of array length. Here's a working fiddle.
What you want is to run a natural sort. For your compare function, replace it with the script mentioned in this article
http://my.opera.com/GreyWyvern/blog/show.dml/1671288
When you do X.sort(), Javascript is comparing your individual arrays as strings. It's basically doing a.toString().localeCompare(b.toString()). This is not what you want.
a.toString() is usually the same as a.join(',')
What I would do is compare each element in the arrays by using a for loop.
Something like this:
X.sort(function(a,b){
// Start off assuming values are equal
var ret = 0;
// Loop through a
for(var a_i = 0, a_length = a.length; a_i < a_length; a_i++){
// If b is shorter than a, it comes first
if(typeof b[a_i] === 'undefined'){
ret = 1;
break;
}
// if the element in a and b are *not* the same, then we can sort
else if(a[a_i] !== b[a_i]){
ret = a[a_i] - b[a_i];
break;
}
}
return ret;
});
You need to sort and compare between the 2 arrays:
http://jsfiddle.net/pXzB6/
var arr = [[10,2],[1,1,3],[2,2]];
arr.sort(function(a,b){
for(var i=0;i<a.length;i++){
var item_a = a[i];
for(var j=0;j<b.length;b++){
var item_b = b[j];
if(item_a == item_b){
continue;
}
else{
return item_a > item_b;
}
}
}
if(a.length == b.length){
return 0;
}
else{
return a.length > b.length;
}
});
console.log(arr);
var points = [40, 100, 1, 5, 25, 10];
points.sort(function(a, b){return a-b});
then the result is :
1,5,10,25,40,100
This is simplest way i think, it's worked.
Trying to get the highest and lowest value from an array that I know will contain only integers seems to be harder than I thought.
var numArray = [140000, 104, 99];
numArray = numArray.sort();
console.log(numArray)
I'd expect this to show 99, 104, 140000. Instead it shows 104, 140000, 99. So it seems the sort is handling the values as strings.
Is there a way to get the sort function to actually sort on integer value?
By default, the sort method sorts elements alphabetically. To sort numerically just add a new method which handles numeric sorts (sortNumber, shown below) -
var numArray = [140000, 104, 99];
numArray.sort(function(a, b) {
return a - b;
});
console.log(numArray);
Documentation:
Mozilla Array.prototype.sort() recommends this compare function for arrays that don't contain Infinity or NaN. (Because Infinity - Infinity is NaN, not 0).
Also examples of sorting objects by key.
Just building on all of the above answers, they can also be done in one line like this:
var numArray = [140000, 104, 99];
numArray = numArray.sort(function (a, b) { return a - b; });
//outputs: 99, 104, 140000
I am surprised why everyone recommends to pass a comparator function to sort(), that makes sorting really slow!
To sort numbers, just create any TypedArray:
var numArray = new Float64Array([140000, 104, 99]);
numArray = numArray.sort();
console.log(numArray)
array.sort does a lexicographic sort by default, for a numeric sort, provide your own function. Here's a simple example:
function compareNumbers(a, b)
{
return a - b;
}
numArray.sort(compareNumbers);
Also note that sort works "in place", there's no need for the assignment.
This answer is equivalent to some of the existing answers, but ECMAScript 6 arrow functions provide a much more compact syntax that allows us to define an inline sort function without sacrificing readability:
numArray = numArray.sort((a, b) => a - b);
It is supported in most browsers today.
The reason why the sort function behaves so weird
From the documentation:
[...] the array is sorted according to each character's Unicode code point
value, according to the string conversion of each element.
If you print the unicode point values of the array then it will get clear.
console.log("140000".charCodeAt(0));
console.log("104".charCodeAt(0));
console.log("99".charCodeAt(0));
//Note that we only look at the first index of the number "charCodeAt( 0 )"
This returns: "49, 49, 57".
49 (unicode value of first number at 140000)
49 (unicode value of first number at 104)
57 (unicode value of first number at 99)
Now, because 140000 and 104 returned the same values (49) it cuts the first index and checks again:
console.log("40000".charCodeAt(0));
console.log("04".charCodeAt(0));
//Note that we only look at the first index of the number "charCodeAt( 0 )"
52 (unicode value of first number at 40000)
40 (unicode value of first number at 04)
If we sort this, then we will get:
40 (unicode value of first number at 04)
52 (unicode value of first number at 40000)
so 104 comes before 140000.
So the final result will be:
var numArray = [140000, 104, 99];
numArray = numArray.sort();
console.log(numArray)
104, 140000, 99
Conclusion:
sort() does sorting by only looking at the first index of the numbers. sort() does not care if a whole number is bigger than another, it compares the value of the unicode of the digits, and if there are two equal unicode values, then it checks if there is a next digit and compares it as well.
To sort correctly, you have to pass a compare function to sort() like explained here.
just do .sort((a, b) => a - b) instead of .sort() itself. In addition to that the array is sorted in place. So return value does not matter.
var numArray = [140000, 104, 99];
numArray.sort((a, b) => a - b);
console.log(numArray)
Ascending
arr.sort((a, b) => a - b);
Descending
arr.sort((a, b) => b - a);
Just for fun:
Descending = Ascending + Reverse
arr.sort((a, b) => a - b).reverse();
I agree with aks, however instead of using
return a - b;
You should use
return a > b ? 1 : a < b ? -1 : 0;
The question has already been answered, the shortest way is to use sort() method. But if you're searching for more ways to sort your array of numbers, and you also love cycles, check the following
Insertion sort
Ascending:
var numArray = [140000, 104, 99];
for (var i = 0; i < numArray.length; i++) {
var target = numArray[i];
for (var j = i - 1; j >= 0 && (numArray[j] > target); j--) {
numArray[j+1] = numArray[j];
}
numArray[j+1] = target
}
console.log(numArray);
Descending:
var numArray = [140000, 104, 99];
for (var i = 0; i < numArray.length; i++) {
var target = numArray[i];
for (var j = i - 1; j >= 0 && (numArray[j] < target); j--) {
numArray[j+1] = numArray[j];
}
numArray[j+1] = target
}
console.log(numArray);
Selection sort:
Ascending:
var numArray = [140000, 104, 99];
for (var i = 0; i < numArray.length - 1; i++) {
var min = i;
for (var j = i + 1; j < numArray.length; j++) {
if (numArray[j] < numArray[min]) {
min = j;
}
}
if (min != i) {
var target = numArray[i];
numArray[i] = numArray[min];
numArray[min] = target;
}
}
console.log(numArray);
Descending:
var numArray = [140000, 104, 99];
for (var i = 0; i < numArray.length - 1; i++) {
var min = i;
for (var j = i + 1; j < numArray.length; j++) {
if (numArray[j] > numArray[min]) {
min = j;
}
}
if (min != i) {
var target = numArray[i];
numArray[i] = numArray[min];
numArray[min] = target;
}
}
console.log(numArray);
Have fun
In JavaScript the sort() method's default behaviour is to sort values in an array alphabetically.
To sort by number you have to define a numeric sort function (which is very easy):
...
function sortNumber(a, b)
{
return a - b;
}
numArray = numArray.sort(sortNumber);
Array.sort uses alphabetic sorting by default instead of numeric .
To support numbers, add like following
var numArray = [140000, 104, 99];
numArray.sort((a, b) => a - b); // <-- Ascending
numArray.sort((a, b) => b - a); // <-- Descending
console.log(numArray);
OUTPUT :
Array.prototype.sort() is the go to method for sorting arrays, but there are a couple of issues we need to be aware of.
The sorting order is by default lexicographic and not numeric regardless of the types of values in the array. Even if the array is all numbers, all values will be converted to string and sorted lexicographically.
So should we need to customize the sort() and reverse() method like below.
Referred URL
For sorting numbers inside the array
numArray.sort(function(a, b)
{
return a - b;
});
For reversing numbers inside the array
numArray.sort(function(a, b)
{
return b - a;
});
Referred URL
to handle undefined, null, and NaN: Null behaves like 0, NaN and undefined goes to end.
array = [3, 5, -1, 1, NaN, 6, undefined, 2, null]
array.sort((a,b) => isNaN(a) || a-b)
// [-1, null, 1, 2, 3, 5, 6, NaN, undefined]
The function 'numerically' below serves the purpose of sorting array of numbers numerically in many cases when provided as a callback function:
function numerically(a, b){
return a-b;
}
array.sort(numerically);
But in some rare instances, where array contains very large and negative numbers, an overflow error can occur as the result of a-b gets smaller than the smallest number that JavaScript can cope with.
So a better way of writing numerically function is as follows:
function numerically(a, b){
if(a < b){
return -1;
} else if(a > b){
return 1;
} else {
return 0;
}
}
While not required in JavaScript, if you would like the sort() compareFunction to strictly return -1, 0, or 1 (similar to how the spaceship operator works in PHP), then you can use Math.sign().
The compareFunction below strictly returns -1, 0, or 1:
numArray.sort((a, b) => Math.sign(a - b));
Note: Math.sign() is not supported in Internet Explorer.
The accepted answer and equivalents like numArray.sort((a,b) => a - b) are great when the array contains only numbers without infinities or NaN. They can be extended to handle infinities and NaN like so:
numArray.sort((a,b) => (+a || 0) - (+b || 0) || 0);
This sorts NaN (or any non-number, like 'foo' or {}) as if it were 0. The final || 0 is needed to handle the case where a and b are equal infinities.
For a normal array of elements values only:
function sortArrayOfElements(arrayToSort) {
function compareElements(a, b) {
if (a < b)
return -1;
if (a > b)
return 1;
return 0;
}
return arrayToSort.sort(compareElements);
}
e.g. 1:
var array1 = [1,2,545,676,64,2,24]
**output : [1, 2, 2, 24, 64, 545, 676]**
var array2 = ["v","a",545,676,64,2,"24"]
**output: ["a", "v", 2, "24", 64, 545, 676]**
For an array of objects:
function sortArrayOfObjects(arrayToSort, key) {
function compareObjects(a, b) {
if (a[key] < b[key])
return -1;
if (a[key] > b[key])
return 1;
return 0;
}
return arrayToSort.sort(compareObjects);
}
e.g. 1: var array1= [{"name": "User4", "value": 4},{"name": "User3", "value": 3},{"name": "User2", "value": 2}]
**output : [{"name": "User2", "value": 2},{"name": "User3", "value": 3},{"name": "User4", "value": 4}]**
Update! Scroll to bottom of answer for smartSort prop additive that gives even more fun!Sorts arrays of anything!
My personal favorite form of this function allows for a param for Ascending, or Descending:
function intArraySort(c, a) {
function d(a, b) { return b - a; }
"string" == typeof a && a.toLowerCase();
switch (a) {
default: return c.sort(function(a, b) { return a - b; });
case 1:
case "d":
case "dc":
case "desc":
return c.sort(d)
}
};
Usage as simple as:
var ara = function getArray() {
var a = Math.floor(Math.random()*50)+1, b = [];
for (i=0;i<=a;i++) b.push(Math.floor(Math.random()*50)+1);
return b;
}();
// Ascending
intArraySort(ara);
console.log(ara);
// Descending
intArraySort(ara, 1);
console.log(ara);
// Ascending
intArraySort(ara, 'a');
console.log(ara);
// Descending
intArraySort(ara, 'dc');
console.log(ara);
// Ascending
intArraySort(ara, 'asc');
console.log(ara);
jsFiddle
Or Code Snippet Example Here!
function intArraySort(c, a) {
function d(a, b) { return b - a }
"string" == typeof a && a.toLowerCase();
switch (a) {
default: return c.sort(function(a, b) { return a - b });
case 1:
case "d":
case "dc":
case "desc":
return c.sort(d)
}
};
function tableExample() {
var d = function() {
var a = Math.floor(50 * Math.random()) + 1,
b = [];
for (i = 0; i <= a; i++) b.push(Math.floor(50 * Math.random()) + 1);
return b
},
a = function(a) {
var b = $("<tr/>"),
c = $("<th/>").prependTo(b);
$("<td/>", {
text: intArraySort(d(), a).join(", ")
}).appendTo(b);
switch (a) {
case 1:
case "d":
case "dc":
case "desc":
c.addClass("desc").text("Descending");
break;
default:
c.addClass("asc").text("Ascending")
}
return b
};
return $("tbody").empty().append(a(), a(1), a(), a(1), a(), a(1), a(), a(1), a(), a(1), a(), a(1))
};
tableExample();
table { border-collapse: collapse; }
th, td { border: 1px solid; padding: .25em .5em; vertical-align: top; }
.asc { color: red; }
.desc { color: blue }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<table><tbody></tbody></table>
.smartSort('asc' | 'desc')
Now have even more fun with a sorting method that sorts an array full of multiple items! Doesn't currently cover "associative" (aka, string keys), but it does cover about every type of value! Not only will it sort the multiple values asc or desc accordingly, but it will also maintain constant "position" of "groups" of values. In other words; ints are always first, then come strings, then arrays (yes, i'm making this multidimensional!), then Objects (unfiltered, element, date), & finally undefineds and nulls!
"Why?" you ask. Why not!
Now comes in 2 flavors! The first of which requires newer browsers as it uses Object.defineProperty to add the method to the Array.protoype Object. This allows for ease of natural use, such as: myArray.smartSort('a'). If you need to implement for older browsers, or you simply don't like modifying native Objects, scroll down to Method Only version.
/* begin */
/* KEY NOTE! Requires EcmaScript 5.1 (not compatible with older browsers) */
;;(function(){if(Object.defineProperty&&!Array.prototype.smartSort){var h=function(a,b){if(null==a||void 0==a)return 1;if(null==b||void 0==b)return-1;var c=typeof a,e=c+typeof b;if(/^numbernumber$/ig.test(e))return a-b;if(/^stringstring$/ig.test(e))return a>b;if(/(string|number){2}/ig.test(e))return/string/i.test(c)?1:-1;if(/number/ig.test(e)&&/object/ig.test(e)||/string/ig.test(e)&&/object/ig.test(e))return/object/i.test(c)?1:-1;if(/^objectobject$/ig.test(e)){a instanceof Array&&a.smartSort("a");b instanceof Array&&b.smartSort("a");if(a instanceof Date&&b instanceof Date)return a-b;if(a instanceof Array&&b instanceof Array){var e=Object.keys(a),g=Object.keys(b),e=e.concat(g).smartSort("a"),d;for(d in e)if(c=e[d],a[c]!=b[c])return d=[a[c],b[c]].smartSort("a"),a[c]==d[0]?-1:1;var f=[a[Object.keys(a)[0]],b[Object.keys(b)[0]]].smartSort("a");return a[Object.keys(a)[0]]==f[0]?-1:1}if(a instanceof Element&&b instanceof Element){if(a.tagName==b.tagName)return e=[a.id,b.id].smartSort("a"),a.id==e[0]?1:-1;e=[a.tagName, b.tagName].smartSort("a");return a.tagName==e[0]?1:-1}if(a instanceof Date||b instanceof Date)return a instanceof Date?1:-1;if(a instanceof Array||b instanceof Array)return a instanceof Array?-1:1;e=Object.keys(a);g=Object.keys(b);e.concat(g).smartSort("a");for(c=0;20>c;c++){d=e[c];f=g[c];if(a.hasOwnProperty(d)&&b.hasOwnProperty(f)){if(a[d]instanceof Element&&b[f]instanceof Element){if(a[d].tagName==b[f].tagName)return c=[a[d].id,b[f].id].smartSort("a"),a[d].id==c[0]?-1:1;c=[a[d].tagName,b[f].tagName].smartSort("d"); return a[d].tagName==c[0]?1:-1}if(a[d]instanceof Element||b[f]instanceof Element)return a[d]instanceof Element?1:-1;if(a[d]!=b[f])return c=[a[d],b[f]].smartSort("a"),a[d]==c[0]?-1:1}if(a.hasOwnProperty(d)&&a[d]instanceof Element)return 1;if(b.hasOwnProperty(f)&&b[f]instanceof Element||!a.hasOwnProperty(d))return-1;if(!b.hasOwnProperty(d))return 1}c=[a[Object.keys(a)[0]],b[Object.keys(b)[0]]].smartSort("d");return a[Object.keys(a)[0]]==c[0]?-1:1}g=[a,b].sort();return g[0]>g[1]},k=function(a,b){if(null== a||void 0==a)return 1;if(null==b||void 0==b)return-1;var c=typeof a,e=c+typeof b;if(/^numbernumber$/ig.test(e))return b-a;if(/^stringstring$/ig.test(e))return b>a;if(/(string|number){2}/ig.test(e))return/string/i.test(c)?1:-1;if(/number/ig.test(e)&&/object/ig.test(e)||/string/ig.test(e)&&/object/ig.test(e))return/object/i.test(c)?1:-1;if(/^objectobject$/ig.test(e)){a instanceof Array&&a.smartSort("d");b instanceof Array&&b.smartSort("d");if(a instanceof Date&&b instanceof Date)return b-a;if(a instanceof Array&&b instanceof Array){var e=Object.keys(a),g=Object.keys(b),e=e.concat(g).smartSort("a"),d;for(d in e)if(c=e[d],a[c]!=b[c])return d=[a[c],b[c]].smartSort("d"),a[c]==d[0]?-1:1;var f=[a[Object.keys(a)[0]],b[Object.keys(b)[0]]].smartSort("d");return a[Object.keys(a)[0]]==f[0]?-1:1}if(a instanceof Element&&b instanceof Element){if(a.tagName==b.tagName)return e=[a.id,b.id].smartSort("d"),a.id==e[0]?-1:1;e=[a.tagName,b.tagName].smartSort("d");return a.tagName==e[0]?-1:1}if(a instanceof Date||b instanceof Date)return a instanceof Date?1:-1;if(a instanceof Array||b instanceof Array)return a instanceof Array?-1:1;e=Object.keys(a);g=Object.keys(b);e.concat(g).smartSort("a");for(c=0;20>c;c++){d=e[c];f=g[c];if(a.hasOwnProperty(d)&&b.hasOwnProperty(f)){if(a[d]instanceof Element&&b[f]instanceof Element){if(a[d].tagName==b[f].tagName)return c=[a[d].id,b[f].id].smartSort("d"),a[d].id==c[0]?-1:1;c=[a[d].tagName,b[f].tagName].smartSort("d");return a[d].tagName==c[0]?-1:1}if(a[d]instanceof Element||b[f]instanceof Element)return a[d]instanceof Element?1:-1;if(a[d]!=b[f])return c=[a[d],b[f]].smartSort("d"),a[d]==c[0]?-1:1}if(a.hasOwnProperty(d)&&a[d]instanceof Element)return 1;if(b.hasOwnProperty(f)&&b[f]instanceof Element)return-1;if(!a.hasOwnProperty(d))return 1;if(!b.hasOwnProperty(d))return-1}c=[a[Object.keys(a)[0]],b[Object.keys(b)[0]]].smartSort("d");return a[Object.keys(a)[0]]==c[0]?-1:1}g=[a,b].sort();return g[0]<g[1]};Object.defineProperty(Array.prototype,"smartSort",{value:function(){return arguments&& (!arguments.length||1==arguments.length&&/^a([sc]{2})?$|^d([esc]{3})?$/i.test(arguments[0]))?this.sort(!arguments.length||/^a([sc]{2})?$/i.test(arguments[0])?h:k):this.sort()}})}})();
/* end */
jsFiddle Array.prototype.smartSort('asc|desc')
Use is simple! First make some crazy array like:
window.z = [ 'one', undefined, $('<span />'), 'two', null, 2, $('<div />', { id: 'Thing' }), $('<div />'), 4, $('<header />') ];
z.push(new Date('1/01/2011'));
z.push('three');
z.push(undefined);
z.push([ 'one', 'three', 'four' ]);
z.push([ 'one', 'three', 'five' ]);
z.push({ a: 'a', b: 'b' });
z.push({ name: 'bob', value: 'bill' });
z.push(new Date());
z.push({ john: 'jill', jack: 'june' });
z.push([ 'abc', 'def', [ 'abc', 'def', 'cba' ], [ 'cba', 'def', 'bca' ], 'cba' ]);
z.push([ 'cba', 'def', 'bca' ]);
z.push({ a: 'a', b: 'b', c: 'c' });
z.push({ a: 'a', b: 'b', c: 'd' });
Then simply sort it!
z.smartSort('asc'); // Ascending
z.smartSort('desc'); // Descending
Method Only
Same as the preceding, except as just a simple method!
/* begin */
/* KEY NOTE! Method `smartSort` is appended to native `window` for global use. If you'd prefer a more local scope, simple change `window.smartSort` to `var smartSort` and place inside your class/method */
window.smartSort=function(){if(arguments){var a,b,c;for(c in arguments)arguments[c]instanceof Array&&(a=arguments[c],void 0==b&&(b="a")),"string"==typeof arguments[c]&&(b=/^a([sc]{2})?$/i.test(arguments[c])?"a":"d");if(a instanceof Array)return a.sort("a"==b?smartSort.asc:smartSort.desc)}return this.sort()};smartSort.asc=function(a,b){if(null==a||void 0==a)return 1;if(null==b||void 0==b)return-1;var c=typeof a,e=c+typeof b;if(/^numbernumber$/ig.test(e))return a-b;if(/^stringstring$/ig.test(e))return a> b;if(/(string|number){2}/ig.test(e))return/string/i.test(c)?1:-1;if(/number/ig.test(e)&&/object/ig.test(e)||/string/ig.test(e)&&/object/ig.test(e))return/object/i.test(c)?1:-1;if(/^objectobject$/ig.test(e)){a instanceof Array&&a.sort(smartSort.asc);b instanceof Array&&b.sort(smartSort.asc);if(a instanceof Date&&b instanceof Date)return a-b;if(a instanceof Array&&b instanceof Array){var e=Object.keys(a),g=Object.keys(b),e=smartSort(e.concat(g),"a"),d;for(d in e)if(c=e[d],a[c]!=b[c])return d=smartSort([a[c], b[c]],"a"),a[c]==d[0]?-1:1;var f=smartSort([a[Object.keys(a)[0]],b[Object.keys(b)[0]]],"a");return a[Object.keys(a)[0]]==f[0]?-1:1}if(a instanceof Element&&b instanceof Element){if(a.tagName==b.tagName)return e=smartSort([a.id,b.id],"a"),a.id==e[0]?1:-1;e=smartSort([a.tagName,b.tagName],"a");return a.tagName==e[0]?1:-1}if(a instanceof Date||b instanceof Date)return a instanceof Date?1:-1;if(a instanceof Array||b instanceof Array)return a instanceof Array?-1:1;e=Object.keys(a);g=Object.keys(b);smartSort(e.concat(g), "a");for(c=0;20>c;c++){d=e[c];f=g[c];if(a.hasOwnProperty(d)&&b.hasOwnProperty(f)){if(a[d]instanceof Element&&b[f]instanceof Element){if(a[d].tagName==b[f].tagName)return c=smartSort([a[d].id,b[f].id],"a"),a[d].id==c[0]?-1:1;c=smartSort([a[d].tagName,b[f].tagName],"a");return a[d].tagName==c[0]?-1:1}if(a[d]instanceof Element||b[f]instanceof Element)return a[d]instanceof Element?1:-1;if(a[d]!=b[f])return c=smartSort([a[d],b[f]],"a"),a[d]==c[0]?-1:1}if(a.hasOwnProperty(d)&&a[d]instanceof Element)return 1; if(b.hasOwnProperty(f)&&b[f]instanceof Element||!a.hasOwnProperty(d))return-1;if(!b.hasOwnProperty(d))return 1}c=smartSort([a[Object.keys(a)[0]],b[Object.keys(b)[0]]],"a");return a[Object.keys(a)[0]]==c[0]?1:-1}g=[a,b].sort();return g[0]>g[1]};smartSort.desc=function(a,b){if(null==a||void 0==a)return 1;if(null==b||void 0==b)return-1;var c=typeof a,e=c+typeof b;if(/^numbernumber$/ig.test(e))return b-a;if(/^stringstring$/ig.test(e))return b>a;if(/(string|number){2}/ig.test(e))return/string/i.test(c)? 1:-1;if(/number/ig.test(e)&&/object/ig.test(e)||/string/ig.test(e)&&/object/ig.test(e))return/object/i.test(c)?1:-1;if(/^objectobject$/ig.test(e)){a instanceof Array&&a.sort(smartSort.desc);b instanceof Array&&b.sort(smartSort.desc);if(a instanceof Date&&b instanceof Date)return b-a;if(a instanceof Array&&b instanceof Array){var e=Object.keys(a),g=Object.keys(b),e=smartSort(e.concat(g),"a"),d;for(d in e)if(c=e[d],a[c]!=b[c])return d=smartSort([a[c],b[c]],"d"),a[c]==d[0]?-1:1;var f=smartSort([a[Object.keys(a)[0]], b[Object.keys(b)[0]]],"d");return a[Object.keys(a)[0]]==f[0]?-1:1}if(a instanceof Element&&b instanceof Element){if(a.tagName==b.tagName)return e=smartSort([a.id,b.id],"d"),a.id==e[0]?-1:1;e=smartSort([a.tagName,b.tagName],"d");return a.tagName==e[0]?-1:1}if(a instanceof Date||b instanceof Date)return a instanceof Date?1:-1;if(a instanceof Array||b instanceof Array)return a instanceof Array?-1:1;e=Object.keys(a);g=Object.keys(b);smartSort(e.concat(g),"a");for(c=0;20>c;c++){d=e[c];f=g[c];if(a.hasOwnProperty(d)&& b.hasOwnProperty(f)){if(a[d]instanceof Element&&b[f]instanceof Element){if(a[d].tagName==b[f].tagName)return c=smartSort([a[d].id,b[f].id],"d"),a[d].id==c[0]?-1:1;c=smartSort([a[d].tagName,b[f].tagName],"d");return a[d].tagName==c[0]?-1:1}if(a[d]instanceof Element||b[f]instanceof Element)return a[d]instanceof Element?1:-1;if(a[d]!=b[f])return c=smartSort([a[d],b[f]],"d"),a[d]==c[0]?-1:1}if(a.hasOwnProperty(d)&&a[d]instanceof Element)return 1;if(b.hasOwnProperty(f)&&b[f]instanceof Element)return-1; if(!a.hasOwnProperty(d))return 1;if(!b.hasOwnProperty(d))return-1}c=smartSort([a[Object.keys(a)[0]],b[Object.keys(b)[0]]],"d");return a[Object.keys(a)[0]]==c[0]?-1:1}g=[a,b].sort();return g[0]<g[1]}
/* end */
Use:
z = smartSort(z, 'asc'); // Ascending
z = smartSort(z, 'desc'); // Descending
jsFiddle Method smartSort(Array, "asc|desc")
Try this code:
HTML:
<div id="demo"></div>
JavaScript code:
<script>
(function(){
var points = [40, 100, 1, 5, 25, 10];
document.getElementById("demo").innerHTML = points;
points.sort(function(a, b){return a-b});
document.getElementById("demo").innerHTML = points;
})();
</script>
Try this code as below
var a = [5, 17, 29, 48, 64, 21];
function sortA(arr) {
return arr.sort(function(a, b) {
return a - b;
})
;}
alert(sortA(a));
TypeScript variant
const compareNumbers = (a: number, b: number): number => a - b
myArray.sort(compareNumbers)
In order to create this kind of sort, you have to pass a function that will check which comes first.
define inside the function which value do you wanna check: a.id - a.id
const myJson = [
{ id: 1, name: 'one'},
{ id: 4, name: 'four'},
{ id: 2, name: 'two'},
{ id: 3, name: 'three'}
];
// provide the sort method to check
const myNewSort = myJson.sort(function(a, b) {
return a.id - b.id;
});
console.log('my new sort',myNewSort)
You can sort number array simply by
const num=[13,17,14,19,16];
let temp;
for(let i=0;i<num.length;i++){
for(let j=i+1;j<num.length;j++){
if(num[i]>num[j]){
temp=num[i]
num[i]=num[j]
num[j]=temp
}
}
}
console.log(num);
let grade =[80,100,50,90,40];
grade.sort((x,y)=> x-y);
grade.forEach(element=>console.log(element));
Sort integers > 0, think outside the box:
function sortArray(arr) {
return new Promise((resolve) => {
const result = []
arr.forEach((item) => {
setTimeout(() => {
result.push(item)
if (result.length === arr.length) resolve(result)
}, item)
})
})
}
sortArray([4, 2, 42, 128, 56, 2]).then((result) => {
document.write(JSON.stringify(result))
})
Note that this should not be used productively, .sort() is better suited for this, check the other answers
sort_mixed
Object.defineProperty(Array.prototype,"sort_mixed",{
value: function () { // do not use arrow function
var N = [], L = [];
this.forEach(e => {
Number.isFinite(e) ? N.push(e) : L.push(e);
});
N.sort((a, b) => a - b);
L.sort();
[...N, ...L].forEach((v, i) => this[i] = v);
return this;
})
try a =[1,'u',"V",10,4,"c","A"].sort_mixed(); console.log(a)
If anyone doesn't understand how Array.sort() works with integers, read this answer.
Alphabetical order:
By default, the sort() method sorts the values as strings in alphabetical and ascending order.
const myArray = [104, 140000, 99];
myArray.sort();
console.log(myArray); // output is [104, 140000, 99]
Ascending order with array.sort(compareFunction):
const myArray = [104, 140000, 99];
myArray.sort(function(a, b){
return a - b;
});
console.log(myArray); // output is [99, 104, 140000]
Explanation from w3schools:
compareFunction defines an alternative sort order. The function should return a negative, zero, or positive value, depending on the arguments, like:
function(a, b){return a-b}
When the sort() method compares two values, it sends the values to the compare function, and sorts the values according to the returned (negative, zero, positive) value.
Example:
When comparing 40 and 100, the sort() method calls the compare
function(40,100).
The function calculates 40-100, and returns -60 (a negative value).
The sort function will sort 40 as a value lower than 100.
Descending order with array.sort(compareFunction):
const myArray = [104, 140000, 99];
myArray.sort(function(a, b){
return b - a;
});
console.log(myArray); // output is [140000, 104, 99]
This time we calculated with b - a(i.e., 100-40) which returns a positive value.
You can get height and lowest number simply by using max() and min() in-built function
var numArray = [140000, 104, 99];
console.log(Math.max(...numArray));
console.log(Math.min(...numArray));
If you want to sort in ascending or descending order
numArray.sort((a, b)=> a - b);
Know more
If you need to calculate and sort the largest charCodeAt from a list of string this is the right way.
const arrayLines = '1.1.1.1\n1.0.1.1\n1.1.1.2\n1.1.1.0'.split('\n');
// Response: (4) ['1.0.1.1', '1.1.1.0', '1.1.1.1', '1.1.1.2']
arrayLines.sort((a, b) => {
let a_charCodeSize = 0,
b_charCodeSize = 0;
// Loop true a & b characters and calculate the charCodeAt size.
for (const aChar of a) a_charCodeSize += aChar.charCodeAt(0);
for (const bChar of b) b_charCodeSize += bChar.charCodeAt(0);
return a_charCodeSize - b_charCodeSize;
});