在 Javascript 中对版本点数字字符串进行排序? [英] Sort version-dotted number strings in Javascript?

查看:22
本文介绍了在 Javascript 中对版本点数字字符串进行排序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下字符串的数组:

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

...等等

我需要一个可以给我以下有序结果的解决方案

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

我尝试实现一种排序,因此它首先按第一个位置的数字排序,而不是在相等的情况下,按第二个位置(第一个点之后)的数字排序,依此类推...

>

我尝试使用 sort()localeCompare(),但如果我有元素 '4.5.0''4.11.0',我把它们排序为 ['4.11.0','4.5.0'],但我需要得到 ['4.5.0','4.11.0'].

我怎样才能做到这一点?

解决方案

您可以将所有部分添加到固定大小的字符串中,然后对其进行排序,最后再次删除填充.

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)

显然,您必须明智地选择数字 100000 的大小:它应该至少比最大的数字部分多一位.

使用正则表达式

无需拆分即可实现相同的操作&加入,当您使用 <代码>替换方法:

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)

只定义一次填充函数

由于填充和它的反向函数非常相似,使用一个函数 f 对两者使用一个函数似乎是一个很好的练习,并使用一个额外的参数定义方向"(1=填充,-1=取消填充).这导致了这个非常晦涩且极端的代码.考虑这只是为了好玩,而不是为了实际使用:

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

使用sort比较回调函数

您可以使用 的比较函数参数sort 实现相同:

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

但是对于较大的数组,这会导致性能降低.这是因为排序算法通常需要多次比较某个值,每次都与数组中的一个不同值.这意味着必须为相同的数字多次执行填充.因此,对于较大的数组,首先在整个数组中应用填充,然后使用标准排序,然后再次删除填充会更快.

但是对于较短的数组,这种方法可能仍然是最快的.在这种情况下,所谓的 natural 排序选项——可以通过 localeCompare 的额外参数实现——将比填充方法更有效:

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

更多关于填充和一元加号

要了解填充的工作原理,请查看它生成的中间结果:

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

关于表达式 +n+100000,注意第一个 +一元加号 是将字符串编码的十进制数转换为其等效数字的最有效方法.添加 100000 使号码具有固定位数.当然,它也可以是 200000 或 300000.请注意,此添加不会更改数字按数字排序时的顺序.

以上只是填充字符串的一种方法.请参阅此问答以了解其他一些替代方法.

I have an array of following strings:

['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 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 a sort so it first sorts by the numbers in the first position, than in case of equality, sort by the numbers in the second position (after the first dot), and so on...

I tried using sort() and localeCompare(), but if I have 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?

解决方案

You could prepend all parts to fixed size strings, then sort that, and finally remove the padding 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 have to choose the size of the number 100000 wisely: it should have at least one more digit than your largest number part will ever have.

With regular expression

The same manipulation can be achieved without having to split & join, when you use the callback argument to 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)

Defining the padding function once only

As both the padding and its reverse functions are so similar, it seemed a nice exercise to use one function f for both, with an extra argument defining the "direction" (1=padding, -1=unpadding). This resulted in this quite 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 compare callback function

You could use the compare function argument of sort 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 larger arrays this will lead to slower performance. This is because the sorting algorithm will often need to compare a certain value several times, each time with a different value from the array. This means that the padding will have to be executed multiple times for the same number. For this reason, it will be faster for larger arrays to first apply the padding in the whole array, then use the standard sort, and then remove the padding again.

But for shorter arrays, this approach might still be the fastest. In that case, the so-called natural sort option -- that can be achieved with the extra arguments of localeCompare -- will be more efficient than the padding 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 about the padding and unary plus

To see how the padding works, look at the intermediate result it generates:

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

Concerning the expression +n+100000, note that the first + is the unary plus and is the most efficient way to convert a string-encoded decimal number to its numerical equivalent. The 100000 is added to make the number have a fixed number of digits. Of course, it could just as well be 200000 or 300000. Note that this addition does not change the order the numbers will have when they would be sorted numerically.

The above is just one way to pad a string. See this Q&A for some other alternatives.

这篇关于在 Javascript 中对版本点数字字符串进行排序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆