Sort an array in specific order javascript - javascript

I have an array like this
arr1 = ["P2.13","P1.13","P4.13","P3.13", "P2.14","P2.14","P1.14","P4.14","P1.15","P2.15","P3.15","P4.15"];
How can I sort the array by the number after the dot FIRST, from 13 to 15, then sort by the number after "P" from 1 to 4? Finaly I want an array like this
arr2 = ["P1.13","P2.13","P3.13","P4.13","P1.14","P2.14","P3.14","P4.14","P1.15","P2.15","P3.15","P4.15"];
Appreciate!!

Pass a function into sort. The following will work for the precise test case provided, but would need to be modified if the input is more general.
arr1.sort(function(a, b) {
return a.slice(-2) - b.slice(-2) || a[1] - b[1];
});
Note that this will mutate arr1.

For programs that include many functional programming I choose Underscore library.
You can directly call sortBy function based on multiple attributes with a hacky trick by joining them. Here is the code:
var sortedArray = _.sortBy(arr1, function(item) {
var nums = item.split('.');
return [nums[1], nums[0]].join("_");
});
However, you can still use Javascript sort function to sort list with customized compare function. Here is the code:
arr1.sort(function(x, y) {
var numsX = x.split('.');
var numsY = y.split('.');
if (numsX[1] !== numsY[1]) {
return compare(numsX[1], numsY[1]); // compare the number after dot first
}
return compare(numsX[0], numsY[0]); // compare the number before dot after
});
// General comparison function for convenience
function compare(x, y) {
if (x === y) {
return 0;
}
return x > y ? 1 : -1;
}
Check two examples on fiddle
Underscore sort vs
Javscript sort
This is my new account, I don't have reputation to post more than 2 links. You can search underscore library.
Thanks.

Related

Get first element in array with index not starting from 0

I'm using a javascript library which returns arrays not starting from zero like starting from 26 or 1500, what i want to do is a method to get the first element in that array regardless of the index number starting with 0 or any other number.
Are they any method to do this in javascript ?
I suggest to use Array#some. You get the first nonsparse element and the index. The iteration stops immediately if you return true in the callback:
var a = [, , 22, 33],
value,
index;
a.some(function (v, i) {
value = v;
index = i;
return true;
});
console.log(index, value);
The information below is generally useful, but for the problem the OP listed, Nina's answer is by far a better solution.
Those are called sparse arrays and they're one of the few situations where you may want to use for-in on an array.
Remember that arrays are objects in JavaScript, and array entries are properties keyed by names (array indexes) that meet certain criteria. So we can use the features that let us discover the properties on an object to find the indexes on your sparse array.
for-in example:
for (var n in theArray) {
if (theArray.hasOwnProperty(n) && isArrayIndex(n)) {
// Use theArray[n]
}
}
This answer shows how you can determine that n is an array index as opposed to being some other property. A very technical definition would be
function isArrayIndex(n) {
return /^0$|^[1-9]\d*$/.test(n) &&
n <= 4294967294;
}
...but a definition that's good enough for most of us would be
function isArrayIndex(n) {
return !isNaN(parseInt(n, 10));
}
Similarly, you can use Object.keys; since it only looks at own enumerable properties, you don't need the hasOwnProperty check:
Object.keys(theArray).forEach(function(n) {
if (isArrayIndex(n)) {
// ...
}
});
Note that officially, neither of those is in any particular order, not even in ES2015 ("ES6"). So in theory, you could see the indexes out of numeric order. In the real world, I've never seen an even vaguely-modern JavaScript engine that returned array indexes out of order. They're not required to, but every one I've tried does.
So officially, you would need to get a full list and then find the minimum value in it:
var min = Object.keys(theArray).reduce(function(min, n) {
var i = parseInt(n, 10);
return isNaN(i) || (min !== undefined && min > i) ? min : i;
}, undefined);
That'll given you undefined if the array is empty, or the min index if it isn't. But if you want to make the assumption you'll get the keys in numeric order:
// Makes an assumption that may not be true
var min = +Object.keys(theArray).filter(isArrayIndex)[0];
If you're using a JavaScript engine that's entirely up-to-date, you can rely on the order returned by Object.getOwnPropertyNames, which is required to list the array indexes in order.
var min = +Object.getOwnPropertyNames(theArray).filter(isArrayIndex)[0];
It may be useful to use a filter function on the array to get back a normalised array.
var fullArray = array.filter(function(n){
return n != undefined;
});
fullArray[0]
The answers here may help you decide Remove empty elements from an array in Javascript
I guess one alternative to Array.prototype.some() is the Array.prototype.findIndex() method. These are much faster than filter alone and will keep your array and indices untouched.
var arr = new Array(1000),
fi = -1;
arr[777] = 1453; // now we have a nice sparse array
fi = arr.findIndex(f => f !== void 0); // void 0 is the perfect undefined
console.log(fi);
console.log(arr[fi]);
With this piece of code you can find first assigned value index and then get the value from your array:
var a = [, , 22, 33];
var value = a.find((v, i) => i in a);
console.log(value);
/* ---------------------------------------------- */
var i = 0
while (!(i in a) && i < a.length) i++; // If i === a.length then the array is emtpy
console.info(i, a[i]);
First implementation uses Array.prototype.find which makes less variable usage so this is cleaner but to find the index you should call indexOf over the array.
But the second one is a little bit old fashioned but give the chance of having index without extra efforts.
BTW Nina's seems better. (can make it shorter?)
const arr = [0,1,2]
// using destructuring to get the first element
let [first] = arr
// plus: using destructuring to get the last element
let [first] = [...arr].reverse()

Sorting arrays within an array by a value

I have a single array looking like this:
var x = [[29,"Abc","9320","390"],[932,"123","9301","9032"], ...]
I'm looking to sort this array, so that it is organised by the first value of each array. In this case, that would look like this:
[[932,"123","9301","9032"], [29,"Abc","9320","390"], ...]
I've attempted to use .forEach but have been unable to get it working. Could anyone offer any suggestions?
Try this:
var x = [[29,"Abc","9320","390"], [932,"123","9301","9032"]];
var sorted = x.sort(function(a, b) {
return b[0] - a[0];
});
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
The proper way to do with sort is this:
var sorted = x.sort(function(a, b) {
return a[0] - b[0];
}).reverse(); // the sort is in ascending order so we need to finally reverse the array to have your final array in descending order!
or even better:
var sorted = x.sort(function(a, b) {
return b[0] - a[0];
})
if you compare the values using a < or > it wont always work:
Sorting in JavaScript: Shouldn't returning a boolean be enough for a comparison function?
However for numbers using a '-' is fine:
How to sort an array of integers correctly

Why do we have functions in sort(), reduce(), map(), filter()?

Can someone explain why these array methods in Javascript have functions as parameters? An example would be:
newArray = oldArray.map(
function(val){
return val + 3;
});
also this,
array.sort(function(a, b) {
return b - a;
});
I am having trouble understanding how these functions and their parameters play a roll in the actual Array methods.
First you need to understand, all JavaScript functions are first class which mean:
A function is an instance of the Object type
A function can have properties and has a link back to its constructor method
You can store the function in a variable
You can pass the function as a parameter to another function
You can return the function from a function
reduce(), sort(), map() and filter() are method of Array object that accept a callback function as its parameter.
For instance:
reduce()
var total = [0, 1, 2, 3].reduce(function(a, b) {
return a + b;
});
sort():
var items = ['réservé', 'premier', 'cliché', 'communiqué', 'café', 'adieu'];
items.sort(function (a, b) {
return a.localeCompare(b);
});
map():
var numbers = [1, 4, 9];
var doubles = numbers.map(function(num) {
return num * 2;
});
filter():
function isBigEnough(value) {
return value >= 10;
}
var filtered = [12, 5, 8, 130, 44].filter(isBigEnough);
Reference:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
This callback functions are used to define behaviour. Like in sort it will sort array in order descending order. That's the definition how you want to sort array or filter array. You can play around it to understand it better or MDN has good examples.
var arr = [12,23,1,56,4,32];
alert(arr.sort());
alert(arr.sort(function(a,b) {
return b - a;
}
));
Here in case of first example sort method will sort by comparing first digit. In order to achieve correct sorting we need to pass our own logic.
You can use sort for various different sorting by changing logic in callback function.
Similar is true for other array methods you mentioned.
In above example of you want to do ascending order you need to
return a - b;
It is functional programming style
To (over) simplify concept is, these function will loop through all members of that array for you. It will just plug that function you pass in at the place it need
Let make an example with map
If you don't use map, the whole thing you need to write is
var oldArray;
var newArray;
for(var i in oldArray){
if(oldArray[i])
newArray.push(oldArray[i] + 3);
}
You could see that everytimes we do something like this. The thing that will change is the line in for block. So they just make a function for it
function map(oldArray,ConvertToSomething){
var newArray;
for(var i in oldArray)
newArray.push(ConvertToSomething(oldArray[i]));
return newArray;
}
var array;
//// The function you pass in here will became that ConvertToSomething above
var newArray = map(array,function(val){ if(val) return val + 3; })
Easy as that. Same go for sort and filter. sort will pick a pair of them for you. filter is like map but it will make an array that exclude thing you don't want by just return false or true

Sort JavaScript array with mixed characters

I am trying to sort an array of names into least to greatest order. Unfortunately JavaScript's .sort() will not work because it has underscores and letters in it.
I have this code:
var array = new Array("S1_FORM", "S2_FORM", "S3_2_FORM", "S3_FORM", "S3_3_FORM", "S4_FORM");
var SortedArray = array.sort();
This should sort it to be like:
S1_FORM, S2_FORM, S3_FORM, S3_2_FORM, S3_3_FORM, S4_FORM
Here's a jsdfiddle:
Your sort is a bit tricky since the _FORM keeps it from being just a straightforward lexicographical sort.
Try this:
var SortedArray = array.sort(function(a, b){
a = a.slice(0, -5);
b = b.slice(0, -5);
return a < b ? -1 : (a > b) ? 1 : 0;
});
I believe you want a custom sort comparison function. See this post:
How to define custom sort function in javascript?
As SHIELDHEAD suggested, you can pass a custom comparator function into Array.sort() when you want to sort by different rules than the default alphabetical/ordinal rules.
The format of the comparator function is as follows:
function(a,b){
// if a should be before b, return -1
// if b should be before a, return 1
// if they are equal, return 0
return a < b ? -1 : a > b ? 1 : 0;
}
In your case, I believe what your comparator function will need to do is grab the substring between "S" and "F" in your strings and compare those.
You can get that substring using regex: a = a.match(/(?!S)([0123456789_])+(?!F)/g);
Here's the working code:
var array = new Array("S1_FORM", "S2_FORM", "S3_2_FORM", "S3_FORM", "S3_3_FORM", "S4_FORM");
array.sort(function(a,b){
a = a.match(/(?!S)([0123456789_])+(?!F)/g);
b = b.match(/(?!S)([0123456789_])+(?!F)/g);
return a < b ? -1 : a === b ? 0 : 1;
});
document.getElementById("output").innerHTML = JSON.stringify(array);
<div id="output"/>
EDIT: Also note that the sort() function changes the original array, so you don't need to create a separate variable to store the sorted array.

JavaScript, array.sort() two arrays based on only one of them

I just discovered array.sort() and saw that I can specify how to sort like this: (example taken from http://www.w3schools.com/jsref/jsref_sort.asp)
var points = [40,100,1,5,25,10];
points.sort(function(a,b){return a-b});
I've been doing my sorting manually just using Bubble Sort because the arrays are small, but I was wondering if array.sort() can be used in place of this:
// Sort rowCategories[i] by rowWidth[i]
swapped = true;
while (swapped) {
swapped = false;
for (var i = 0; i < rowCategories.length-1; i++) {
if (rowWidth[i] < rowWidth[i+1]) {
var swap = rowCategories[i];
rowCategories[i] = rowCategories[i+1];
rowCategories[i+1] = swap;
swap = rowWidth[i];
rowWidth[i] = rowWidth[i+1];
rowWidth[i+1] = swap;
swapped = true;
}
}
}
What would I write for the built in sort to do the equivalent work?
There is a way of multi sorting arrays but I like the array of objects better. Here is the multi sort:
function multisort(sortBy,otherArrays){
var keys=[],i,tmpKeys;
sortBy.sort(function(a,b){
var ret=(a>b)?1:(a<b)?-1:0;
// storing the return values to be used for the other arrays
keys.push(ret);
return ret;
});
for(i=0;i<otherArrays.length;i++){
// copy the stored retun values
tmpKeys=keys.concat([]);
otherArrays[i].sort(function(){
// return the saved values based on sortBy array's sort
return tmpKeys.splice(0,1);
});
}
}
var arr1=[1,2,3],
arr2=[5,6,7],
reverse=["c","b","a"];
multisort(reverse,[arr1,arr2])
console.log(arr1);
console.log(arr2);
console.log(reverse);
Sorting by object key:
var arr=[
{id:1,col1:3,col2:2},
{id:2,col1:2,col2:2},
{id:3,col1:1,col2:1}
];
function sortBy(arr,keys){
var i=0;
arr.sort(function(a,b){
var i=0;
while(a[keys[i]]===b[keys[i]]&&i<keys.length){
i++;
}
return (keys.length===i)?0:(a[keys[i]]>b[keys[i]])?1:-1;
});
}
//sort by col2 then col1
sortBy(arr,["col2","col1"]);
console.log(arr);
//sort by id
sortBy(arr,["id"]);
console.log(arr);
this only requires a little modification. Instead of storing two arrays store one array with an object with the two attributes. Then you can do something like this.
arr.sort(functiona(a,b){return a.rowWidth - b.rowWidth});
the object must contain the attributes rowWidth and rowCatagories
The built-in sort() can only sort one array at a time, and the comparison is based on the values, not the indexes.
What you're doing is similar to PHP's array_multisort() function. If you use load the php.js library, it includes an implementation of this function. The implementation is here.
Actually the vanilla the sort function uses depends on browser JS engine implementation, for instance Mozilla uses MergeSort I believe.
By default it compare array items as strings and if you need any other consideration you must pass your own compare function to sort and function must return negative, 0 or positive number indicating the items comparison result.
You can use this sort function instead of yours, that would be much faster.

Categories

Resources