sort an alphanumeric array - javascript

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());
}

Related

Sort array alphanumerically [duplicate]

This question already has answers here:
Sort mixed alpha/numeric array
(18 answers)
Closed 3 years ago.
I have array like below , I want to sort it alphanumerically by ascending or descending in faster way.
[
"NFO:BANKNIFTY1931428900CE",
"NFO:BANKNIFTY1931429000CE",
"NFO:BANKNIFTY1931429500CE",
"NFO:BANKNIFTY1931429400CE",
"NFO:BANKNIFTY1931429300CE",
"NFO:BANKNIFTY1931429200CE"
]
I want to sort it like below , descending or ascending
[
"NFO:BANKNIFTY1931429500CE",
"NFO:BANKNIFTY1931429400CE",
"NFO:BANKNIFTY1931429300CE",
"NFO:BANKNIFTY1931429200CE",
"NFO:BANKNIFTY1931429000CE",
"NFO:BANKNIFTY1931428900CE",
]
I tried something like below , but it does not sort properly and its slow too.
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());
}
Note: Sometimes it can involve mix of lowercase letters.
Simply use .sort().
var items = [
"NFO:BANKNIFTY1931428900CE",
"NFO:BANKNIFTY1931429000CE",
"NFO:BANKNIFTY1931429500CE",
"NFO:BANKNIFTY1931429400CE",
"NFO:BANKNIFTY1931429300CE",
"NFO:BANKNIFTY1931429200CE"
]
var sorted = items.sort()
console.log(sorted);

How to sort set of numbers both lexicographically and numerically?

I currently have a set of strings that are both just numbers and number with + or -. Such as follows :
1 , 1+, 1-, 2, 2+, 2-, 10
Which when I sort using JavaScript's sort functions gives out:
1, 1+ , 1-, 10, 2, 2+, 2-
which is lexicographically orders but not numerically. Is there a way to sort this so the numbers come out in the correct way(the first list) ? I am using ExtJS stores so an answers as a store sorter is preferred but plain javascript is also fine. Thanks ?
Edit: This is not just sorting numbers.
You can use a custom ordering function like so:
var numbers = ['1', '1-', '1+', '2', '2+', '2-', '10'];
numbers.sort(function (a, b){
var _a = parseFloat(a), // If the values are integers only, parseInt will do too
_b = parseFloat(b);
if (_a - _b === 0) {
return (a > b) ? 1 : -1;
} else {
return _a - _b;
}
});
console.log(numbers);
The function checks whether the number values are equal, and if so, falls back to lexicographic ordering to sort the character suffixes. If there are no suffixes in equal-case, hence no matter in which order the numbers are returned. If only one of the operands has a suffix, bare number returns negative. If the number values are not equal, the function simply returns the tristate, i.e a - b, which will be evaluated to one of negative, 0, positive. Or actually it's "bistate", since we've handled 0 case already.
More generic solution
The code above is rather a special case for two different single charactered suffixes only. If suffixes are more complex, here's a more generic code to sort by number and by suffixes:
var numbers = ['1', '1-r', '1+q', '1', '2', '2+q', '2-r', '10'];
function suffixSort (suff, asc) {
asc = 2 * +(!!asc) - 1; // Convert boolean to -1 or 1
return function (a, b) {
var _a = parseFloat(a), // Extract the number value
_b = parseFloat(b),
aSI = -(a.length - _a.toString().length), // Get the index of suffix start
bSI = -(b.length - _b.toString().length);
// Equal number values, sort by suffixes
if (_a === _b) {
return (suff.indexOf(a.substr(aSI)) > suff.indexOf(b.substr(bSI))) ? 1 : -1;
}
// Inequal number values, sort by numbers
return asc * (_a - _b);
}
}
// suffixSort arguments
// suff: An array of the suffix strings to sort, ordered in the desired sorting order
// asc: true = ascending, false = descending. Optional, defaults to descending sort
numbers.sort(suffixSort(['+q', '-r'], true));
console.log(numbers);
The idea is to store the suffixes into an array, and when suffix sorting is needed, function compares the array indices of the suffixes instead of the suffixes themselves.
suffixSort lets you also to decide the sorting direction. Selected sorting direction doesn't have an effect on suffix sorting, they are always returned in the order they appear in suff array.
These values are almost integers, so comparing them according to praseInt will almost get you there. The only thing missing is a special treatment for values that have the same integer part where x- should come first, then x and finally x+:
function specialChar(s) {
c = s.substr(-1);
if (c == '+') {
return 1;
}
if (c == '-') {
return -1;
}
return 0;
}
function numCompare(a, b) {
aNum = parseInt(a);
bNum = parseInt(b);
cmp = aNum - bNum;
if (cmp != 0) {
return cmp;
}
// Integer parts are equal - compare the special char at the end
return specialChar(a) - specialChar(b);
}
arr = ['1' , '1+', '1-', '2', '2+', '2-', '10'];
arr.sort(numCompare);
var result=[];
result=array.map(function(n){
if(typeof n==='number') return n;
if(n[n.length-1]=='+'){
return parseInt(n.substring(0,n.length-1))
}
else if(n[n.length-1]=='-'){
return 0-parseInt(n.substring(0,n.length-1))
}
});
result.sort(function(a,b){return a-b})
You could use Array#sort and split the elements in numbers and the rest, then return the difference or the difference of the order.
var array = ['10', '2', '2+', '2-', '1', '1+', '1-'];
array.sort(function (a, b) {
var r = /\d+|\D+/g,
aa = a.match(r),
bb = b.match(r),
order = { '+': 1, '-': 2 };
return aa[0] - bb[0] || (order[aa[1]] || 0) - (order[bb[1]] || 0);
});
console.log(array);
If there are only three possible states of a number, and the states have the order number, number+, number the states can be recreated by creating an array representation of the numbers, removing the unique numbers from array, from minimum to maximum, concatenating empty string or arithmetic operator in required order to the number, then pushing the value to an array, where .toString() can be used to view the comma separated string representation of the sorted values within the array
var str = `314+, 1-, 7+, 1, 1-, 271-, 10-
, 10+, 271, 271+, 314-, 314
, 10, 2-, 2, 2+, 7-, 7`;
for (var [nums, order, res, num] = [str.match(/\d+/g), ["", "+", "-"], [], null]
; nums.length
; num = Math.min.apply(Math, nums)
, res = [...res, ...order.map(op => num + op)]
, nums = nums.filter(n => n != num)
);
console.log(res.toString() + "\n", res);
Assuming that you just want to throw away the symbols, then you could use parseInt and Array#sort to get order numerically.
var data = ['1' , '1+', '1-', '2', '2+', '2-', '10'];
var sortedData = data.sort(function(a,b){return parseInt(a)-parseInt(b);});

Why isn't this sorting correctly?

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...

sorting of array manually in javascript

I have an array of strings like below.
ABC
QRS
DEF
HIJ
TUV
KLM
NOP
I need to sort this array in javascript in alphabetical order, except for few values which is already known. ie I need DEF and NOP comes in the first 2 positions and sort rest of the array alphabetically in ascending order. Here is what I've written to sort the entire array in alphabetical order, now I need the 2 values in the first 2 positions.
array.sort(function(a,b){return ((a < b) ? -1 : (a > b) ? 1 : 0)});
Expected result.
DEF
NOP
ABC
HIJ
KLM
QRS
TUV
The contents of the array is dynamic, so if the array has DEF or NOP, then those should be on top, if else, it should be sorted alphabetically. Whats the best way to approach this?
I think the most straightforward way would be to remove the known elements separately instead of trying to incorporate them into the sort. That way, you can also just sort without a comparison function.
function sortWithKnownPrefix(prefix, arr) {
// Get the non-prefix elements
var rest = arr.filter(function (item) {
return prefix.indexOf(item) === -1;
});
// Concatenate the prefix and the sorted non-prefix elements
return prefix.concat(rest.sort());
}
sortWithKnownPrefix(
["DEF", "NOP"],
["ABC", "QRS", "DEF", "HIJ", "TUV", "KLM", "NOP"]
)
// ["DEF", "NOP", "ABC", "HIJ", "KLM", "QRS", "TUV"]
If you want to allow for, count and hoist multiple instances of those strings: http://jsfiddle.net/4hgnjqas/1/
The following will count all known instances of the strings you want to hoist to the front, remove them from the existing array, sort it, then add the same number of "DEF"s and "NOP"s to the array.
var hoist = {"NOP":0, "DEF":0}
for(var p in hoist)
while(array.indexOf(p)>-1){
array.splice(array.indexOf(p),1);
hoist[p]++;
}
arr.sort();
for(var p in hoist){
for(var i=0;i<hoist[p];i++)
array.unshift(p);
}
console.log(array);
This will reposition 'DEF' and 'NOP' after sorting the rest of the items:
function customSort(array) {
array = array.sort(function(a,b){
return (a < b) ? -1 : (a > b) ? 1 : 0;
});
var NOPIndex = array.indexOf('NOP');
if (NOPIndex > -1)
array.unshift(array.splice(NOPIndex, 1)[0]);
var DEFIndex = array.indexOf('DEF');
if (DEFIndex > -1)
array.unshift(array.splice(DEFIndex, 1)[0]);
return array;
}
this could be the simpler one
var arr = ['ABC','QRS','DEF','HIJ','TUV','KLM','NOP']
var exclude = ['DEF', 'NOP'];
arr.sort(function(a,b) {
if(exclude.indexOf(a) > -1 && exclude.indexOf(b) > -1)
return ((a < b) ? -1 : (a > b) ? 1 : 0);
if(exclude.indexOf(b) > -1)
return 1;
return ((a < b) ? -1 : (a > b) ? 1 : 0)
});
alert(JSON.stringify(arr)) //result
JS Fiddle *UPDATED

.sort not working with Firefox

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])

Categories

Resources