Sorting lines with line numbers in Javascript format?

I have an array of the following lines:

['5.5.1', '4.21.0', '4.22.0', '6.1.0', '5.1.0', '4.5.0'] 

... etc..

I need a solution that will give me the following ordered result

 ['4.5.0', '4.21.0', '4.22.0', '5.1.0', '5.5.1', '6.1.0']. 

I tried to implement sorting to first sort by numbers in the first position than in case of equality, sort by numbers in the second position (after the first point) and so on ...

I tried using sort () and localeCompare () , but if I have the elements '4.5.0' and '4.11.0' , I get them sorted as ['4.11.0','4.5.0'] , but I need to get ['4.5.0','4.11.0'] .

How can i achieve this?

+9
source share
10 answers

You can add all parts to lines of a fixed size, then sort them and finally remove the indentation again.

 var arr = ['5.5.1', '4.21.0', '4.22.0', '6.1.0', '5.1.0', '4.5.0']; arr = arr.map( a => a.split('.').map( n => +n+100000 ).join('.') ).sort() .map( a => a.split('.').map( n => +n-100000 ).join('.') ); console.log(arr) 

Obviously, you should choose the size of the number 100000 wisely: it must have at least one digit more than your largest part of the number will ever be.

With regex

The same manipulation can be achieved without splitting and joining when you use the callback argument for the replace method:

 var arr = ['5.5.1', '4.21.0', '4.22.0', '6.1.0', '5.1.0', '4.5.0']; arr = arr.map( a => a.replace(/\d+/g, n => +n+100000 ) ).sort() .map( a => a.replace(/\d+/g, n => +n-100000 ) ); console.log(arr) 

Define the fill function only once

Since the fill functions and inverse functions are very similar, it would be nice to use one function f for both functions with an additional argument that defines the "direction" (1 = fill, -1 = expand). This led to this rather obscure and extreme code. Consider this just for fun, not for real use:

 var arr = ['5.5.1', '4.21.0', '4.22.0', '6.1.0', '5.1.0', '4.5.0']; arr = (f=>f(f(arr,1).sort(),-1)) ((arr,v)=>arr.map(a=>a.replace(/\d+/g,n=>+n+v*100000))); console.log(arr); 

Use the sort callback function

You can use the argument of the sort comparison function to achieve the same:

 arr.sort( (a, b) => a.replace(/\d+/g, n => +n+100000 ) .localeCompare(b.replace(/\d+/g, n => +n+100000 )) ); 

But for large arrays, this will lead to reduced performance. This is because the sorting algorithm often needs to compare a certain value several times, each time with a different value from the array. This means that the filling must be done several times for the same number. For this reason, for large arrays, it will be faster to first apply padding to the entire array, then use standard sorting, and then delete the padding again.

But for shorter arrays, this approach may be the fastest. In this case, the so-called natural sorting option, which can be achieved with the optional localeCompare arguments localeCompare will be more efficient than the fill method:

 var arr = ['5.5.1', '4.21.0', '4.22.0', '6.1.0', '5.1.0', '4.5.0']; arr = arr.sort( (a, b) => a.localeCompare(b, undefined, { numeric:true }) ); console.log(arr); 

More on padding and single plus

To see how the add-on works, look at the intermediate result that it generates:

 [ "100005.100005.100001", "100004.100021.100000", "100004.100022.100000", "100006.100001.100000", "100005.100001.100000" ] 

Regarding the expression +n+100000 , note that the first + is a unary plus and is the most efficient way to convert a string decimal number to its numerical equivalent. 100000 is added so that the number has a fixed number of digits. Of course, it can also be 200,000 or 300,000. Note that this add-on does not change the order in which numbers will be arranged in numerical sorting.

Above is just one way to complete a line. See this question and answers for some other alternatives.

+25
source

You can split lines and compare parts.

 function customSort(data, order) { function isNumber(v) { return (+v).toString() === v; } var sort = { asc: function (a, b) { var i = 0, l = Math.min(a.value.length, b.value.length); while (i < l && a.value[i] === b.value[i]) { i++; } if (i === l) { return a.value.length - b.value.length; } if (isNumber(a.value[i]) && isNumber(b.value[i])) { return a.value[i] - b.value[i]; } return a.value[i].localeCompare(b.value[i]); }, desc: function (a, b) { return sort.asc(b, a); } }, mapped = data.map(function (el, i) { return { index: i, value: el.split('') }; }); mapped.sort(sort[order] || sort.asc); return mapped.map(function (el) { return data[el.index]; }); } var array = ['5.5.1', '4.21.0', '4.22.0', '6.1.0', '5.1.0']; console.log('sorted array asc', customSort(array)); console.log('sorted array desc ', customSort(array, 'desc')); console.log('original array ', array); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 
+1
source

You can check the loop if the values ​​are different, the inverse difference, else continue

 var a=['5.5.1', '4.21.0', '4.22.0', '6.1.0', '5.1.0', '4.5.0']; a.sort(function(a,b){ var a1 = a.split('.'); var b1 = b.split('.'); var len = Math.max(a1.length, b1.length); for(var i = 0; i< len; i++){ var _a = +a1[i] || 0; var _b = +b1[i] || 0; if(_a === _b) continue; else return _a > _b ? 1 : -1 } return 0; }) console.log(a) 
+1
source

This seems to work if there are only numbers between the points:

 var a = ['5.5.1', '4.21.0', '4.22.0', '6.1.0', '5.1.0', '4.5.0'] a = a.map(function (x) { return x.split('.').map(function (x) { return parseInt(x) }) }).sort(function (a, b) { var i = 0, m = a.length, n = b.length, o, d o = m < n ? n : m for (; i < o; ++i) { d = (a[i] || 0) - (b[i] || 0) if (d) return d } return 0 }).map(function (x) { return x.join('.') }) 
0
source

Although a little late this would be my decision;

 var arr = ["5.1.1","5.1.12","5.1.2","3.7.6","2.11.4","4.8.5","4.8.4","2.10.4"], sorted = arr.sort((a,b) => {var aa = a.split("."), ba = b.split("."); return +aa[0] < +ba[0] ? -1 : aa[0] === ba[0] ? +aa[1] < +ba[1] ? -1 : aa[1] === ba[1] ? +aa[2] < +ba[2] ? -1 : 1 : 1 : 1; }); console.log(sorted); 
0
source
 'use strict'; var arr = ['5.1.2', '5.1.1', '5.1.1', '5.1.0', '5.7.2.2']; Array.prototype.versionSort = function () { var arr = this; function isNexVersionBigger (v1, v2) { var a1 = v1.split('.'); var b2 = v2.split('.'); var len = a1.length > b2.length ? a1.length : b2.length; for (var k = 0; k < len; k++) { var a = a1[k] || 0; var b = b2[k] || 0; if (a === b) { continue; } else return b < a; } } for (var i = 0; i < arr.length; i++) { var min_i = i; for (var j = i + 1; j < arr.length; j++) { if (isNexVersionBigger(arr[i], arr[j])) { min_i = j; } } var temp = arr[i]; arr[i] = arr[min_i]; arr[min_i] = temp; } return arr; } console.log(arr.versionSort()); 
0
source

This solution takes into account version numbers, which may not be in full format with 3 parts (for example, if one of the version numbers is only 2 or 2.0 or 0.1, etc.).

The user-defined sorting function that I wrote is probably basically what you are looking for, it just needs an array of objects in the format {"major":X, "minor":X, "revision":X} :

 var versionArr = ['5.5.1', '4.21.0', '4.22.0', '6.1.0', '5.1.0', '4.5.0']; var versionObjectArr = []; var finalVersionArr = []; /* split each version number string by the '.' and separate them in an object by part (major, minor, & revision). If version number is not already in full, 3-part format, -1 will represent that part of the version number that didn't exist. Push the object into an array that can be sorted. */ for(var i = 0; i < versionArr.length; i++){ var splitVersionNum = versionArr[i].split('.'); var versionObj = {}; switch(splitVersionNum.length){ case 1: versionObj = { "major":parseInt(splitVersionNum[0]), "minor":-1, "revision":-1 }; break; case 2: versionObj = { "major":parseInt(splitVersionNum[0]), "minor":parseInt(splitVersionNum[1]), "revision":-1 }; break; case 3: versionObj = { "major":parseInt(splitVersionNum[0]), "minor":parseInt(splitVersionNum[1]), "revision":parseInt(splitVersionNum[2]) }; } versionObjectArr.push(versionObj); } //sort objects by parts, going from major to minor to revision number. versionObjectArr.sort(function(a, b){ if(a.major < b.major) return -1; else if(a.major > b.major) return 1; else { if(a.minor < b.minor) return -1; else if(a.minor > b.minor) return 1; else { if(a.revision < b.revision) return -1; else if(a.revision > b.revision) return 1; } } }); /* loops through sorted object array to recombine it version keys to match the original string value. If any trailing parts of the version number are less than 0 (ie they didn't exist so we replaced them with -1) then leave that part of the version number string blank. */ for(var i = 0; i < versionObjectArr.length; i++){ var versionStr = ""; for(var key in versionObjectArr[i]){ versionStr = versionObjectArr[i].major; versionStr += (versionObjectArr[i].minor < 0 ? '' : "." + versionObjectArr[i].minor); versionStr += (versionObjectArr[i].revision < 0 ? '' : "." + versionObjectArr[i].revision); } finalVersionArr.push(versionStr); } console.log('Original Array: ',versionArr); console.log('Expected Output: ',['4.5.0', '4.21.0', '4.22.0', '5.1.0', '5.5.1', '6.1.0']); console.log('Actual Output: ', finalVersionArr); 
0
source

If ES6 I do this:

 versions.sort((v1, v2) => { let [, major1, minor1, revision1 = 0] = v1.match(/([0-9]+)\.([0-9]+)(?:\.([0-9]+))?/); let [, major2, minor2, revision2 = 0] = v2.match(/([0-9]+)\.([0-9]+)(?:\.([0-9]+))?/); if (major1 != major2) return parseInt(major1) - parseInt(major2); if (minor1 != minor2) return parseInt(minor1) - parseInt(major2); return parseInt(revision1) - parseInt(revision2); }); 
0
source

Inspired by the accepted answer, but compatible with ECMA5 and with regular string filling (see my comments for the answer):

 function sortCallback(a, b) { function padParts(version) { return version .split('.') .map(function (part) { return '00000000'.substr(0, 8 - part.length) + part; }) .join('.'); } a = padParts(a); b = padParts(b); return a.localeCompare(b); } 

Using:

 ['1.1', '1.0'].sort(sortCallback); 
0
source
 **Sorted Array Object by dotted version value** var sampleData = [ { name: 'Edward', value: '2.1.2' }, { name: 'Sharpe', value: '2.1.3' }, { name: 'And', value: '2.2.1' }, { name: 'The', value: '2.1' }, { name: 'Magnetic', value: '2.2' }, { name: 'Zeros', value: '0' }, { name: 'Zeros', value: '1' } ]; arr = sampleData.map( a => a.value).sort(); var requireData = []; arr.forEach(function(record, index){ var findRecord = sampleData.find(arr => arr.value === record); if(findRecord){ requireData.push(findRecord); } }); console.log(requireData); [check on jsfiddle.net][1] [1]: https://jsfiddle.net/jx3buswq/2/ It is corrected now!!! 
-1
source

Source: https://habr.com/ru/post/1258658/


All Articles