I would like to sort an array of strings (in javascript) such that groups of digits within the strings are compared as integers not strings. I am not worried about signed or floating point numbers.
我想对字符串数组(在javascript中)进行排序,以便将字符串中的数字组作为整数而不是字符串进行比较。我不担心签名或浮点数。
for example, the result should be ["a1b3","a9b2","a10b2","a10b11"]
not ["a1b3","a10b11","a10b2","a9b2"]
例如,结果应该是["a1b3","a9b2","a10b2","a10b11"]而不是["a1b3","a10b11","a10b2","a9b2"]
The easiest way to do this seems to be splitting each string on boundaries around groups of digits. Is there a pattern I can pass to String.split to split on character boundaries without removing any characters?
要做到这一点,最简单的方法似乎是在一组数字的边界上分割每个字符串。是否有一个模式可以传递给字符串。在没有删除任何字符的情况下分割到分割字符边界?
"abc11def22ghi".split(/?/) = ["abc","11","def","22","ghi"];
“abc11def22ghi .split(/ /)=(“abc”、“十一”、“def”,“22”、“全球健康行动计划”);
Or is there another way to compare strings that does not involve splitting them up, perhaps by padding all groups of digits with leading zeros so they are the same length?
或者有没有其他方法来比较不需要分割的字符串,比如用前导0填充所有的数字组,使它们的长度相同?
"aa1bb" => "aa00000001bb", "aa10bb" => "aa00000010bb"
"aa1bb" => "aa00000001bb" "aa10bb" => "aa00000010bb"
I am working with arbitrary strings, not strings that have a specific arrangement of digit groups.
我使用的是任意的字符串,而不是有特定数字组排列的字符串。
Edit:
编辑:
I like the /(\d+)/
one liner from Gaby to split the array. How backwards compatible is that?
我喜欢/(\d+)/一行从Gaby拆分数组。向后兼容的程度如何?
The solutions that parse the strings once in a way that can be used to rebuild the originals are much more efficient that this compare function. None of the answers handle some strings starting with digits and others not, but that would be easy enough to remedy and was not explicit in the original question.
用一种可用于重新构建原始字符串的方式解析字符串的解决方案比这个compare函数要高效得多。所有的答案都不能处理一些以数字开头的字符串,而其他的则不能,但这很容易纠正,而且在最初的问题中也不明确。
["a100","a20","a3","a3b","a3b100","a3b20","a3b3","!!","~~","9","10","9.5"].sort( function ( inA , inB ) {
var result = 0;
var a , b , pattern = /(\d+)/;
var as = inA.split( pattern );
var bs = inB.split( pattern );
var index , count = as.length;
if ( ( '' === as[0] ) === ( '' === bs[0] ) ) {
if ( count > bs.length ) count = bs.length;
for ( index = 0 ; index < count && 0 === result ; ++index ) {
a = as[index]; b = bs[index];
if ( index & 1 ) {
result = a - b;
} else {
result = !( a < b ) ? ( a > b ) ? 1 : 0 : -1;
}
}
if ( 0 === result ) result = as.length - bs.length;
} else {
result = !( inA < inB ) ? ( inA > inB ) ? 1 : 0 : -1;
}
return result;
} ).toString();
result: "!!,9,9.5,10,a3,a3b,a3b3,a3b20,a3b100,a20,a100,~~"
9.5结果:“! !,9日,10日,a3,a3b,a3b3,a3b20,a3b100,a20,a100,~ ~”
6 个解决方案
#1
10
I think this does what you want
我想这就是你想要的
function sortArray(arr) {
var tempArr = [], n;
for (var i in arr) {
tempArr[i] = arr[i].match(/([^0-9]+)|([0-9]+)/g);
for (var j in tempArr[i]) {
if( ! isNaN(n = parseInt(tempArr[i][j])) ){
tempArr[i][j] = n;
}
}
}
tempArr.sort(function (x, y) {
for (var i in x) {
if (y.length < i || x[i] < y[i]) {
return -1; // x is longer
}
if (x[i] > y[i]) {
return 1;
}
}
return 0;
});
for (var i in tempArr) {
arr[i] = tempArr[i].join('');
}
return arr;
}
alert(
sortArray(["a1b3", "a10b11", "a10b2", "a9b2"]).join(",")
);
#2
5
Assuming what you want to do is just do a numeric sort by the digits in each array entry (ignoring the non-digits), you can use this:
假设您要做的是根据每个数组条目中的数字进行数字排序(忽略非数字),您可以使用以下方法:
function sortByDigits(array) {
var re = /\D/g;
array.sort(function(a, b) {
return(parseInt(a.replace(re, ""), 10) - parseInt(b.replace(re, ""), 10));
});
return(array);
}
It uses a custom sort function that removes the digits and converts to a number each time it's asked to do a comparison. You can see it work here: http://jsfiddle.net/jfriend00/t87m2/.
它使用自定义排序函数,每次请求进行比较时,它会删除数字并转换为数字。您可以在这里看到它的工作:http://jsfiddle.net/jfriend00/t87m2/。
If this isn't what you want, then please clarify as your question is not very clear on hwo the sort should actually work.
如果这不是你想要的,那么请澄清,因为你的问题不是很清楚的hwo类型应该是有效的。
#3
4
Use this compare function for sorting ..
使用这个比较函数进行排序。
function compareLists(a,b){
var alist = a.split(/(\d+)/), // split text on change from anything to digit and digit to anything
blist = b.split(/(\d+)/); // split text on change from anything to digit and digit to anything
alist.slice(-1) == '' ? alist.pop() : null; // remove the last element if empty
blist.slice(-1) == '' ? blist.pop() : null; // remove the last element if empty
for (var i = 0, len = alist.length; i < len;i++){
if (alist[i] != blist[i]){ // find the first non-equal part
if (alist[i].match(/\d/)) // if numeric
{
return +alist[i] - +blist[i]; // compare as number
} else {
return alist[i].localeCompare(blist[i]); // compare as string
}
}
}
return true;
}
Syntax
语法
var data = ["a1b3","a10b11","b10b2","a9b2","a1b20","a1c4"];
data.sort( compareLists );
alert(data);
demo at http://jsfiddle.net/h9Rqr/7/
演示http://jsfiddle.net/h9Rqr/7/
#4
1
Here's a more complete solution that sorts according to both letters and numbers in the strings
这里有一个更完整的解决方案,根据字符串中的字母和数字进行排序
function sort(list) {
var i, l, mi, ml, x;
// copy the original array
list = list.slice(0);
// split the strings, converting numeric (integer) parts to integers
// and leaving letters as strings
for( i = 0, l = list.length; i < l; i++ ) {
list[i] = list[i].match(/(\d+|[a-z]+)/g);
for( mi = 0, ml = list[i].length; mi < ml ; mi++ ) {
x = parseInt(list[i][mi], 10);
list[i][mi] = !!x || x === 0 ? x : list[i][mi];
}
}
// sort deeply, without comparing integers as strings
list = list.sort(function(a, b) {
var i = 0, l = a.length, res = 0;
while( res === 0 && i < l) {
if( a[i] !== b[i] ) {
res = a[i] < b[i] ? -1 : 1;
break;
}
// If you want to ignore the letters, and only sort by numbers
// use this instead:
//
// if( typeof a[i] === "number" && a[i] !== b[i] ) {
// res = a[i] < b[i] ? -1 : 1;
// break;
// }
i++;
}
return res;
});
// glue it together again
for( i = 0, l = list.length; i < l; i++ ) {
list[i] = list[i].join("");
}
return list;
}
#5
0
Sorting occurs from left to right unless you create a custom algorithm. Letters or digits are compared digits first then letters.
排序从左到右进行,除非您创建一个自定义算法。字母或数字首先是数字,然后是字母。
However, what you want to accomplish as per your own example (a1, a9, a10) WON'T EVER HAPPEN. That would require you knowing the data before hand and spliting the string in every possible way before applying the sorting.
但是,您希望按照自己的示例(a1、a9、a10)完成的任务不会发生。这将要求您事先知道数据,并在应用排序之前以各种可能的方式分割字符串。
One final alternative would be:
最后一种选择是:
a) break each and every string from left to right whenever is a change from letter to digit and vice versa; & b) then start the sorting on those groups from RIGHT-TO-LEFT. That will be a very demanding algorithm. Can be done!
a)每当从字母到数字发生变化时,将每个字符串从左到右分开,反之亦然;然后开始从右到左对这些组进行排序。这将是一个非常苛刻的算法。可以做!
Finally, if you are the GENERATOR of the original "text", you should consider NORMALIZING the output where a1 a9 a10 could be outputed as a01 a09 a10. This way you could have full cotnrol of the final version of the algorithm.
最后,如果您是原始“文本”的生成者,您应该考虑规范化输出,其中a1 a9 a10可以输出为a01 a09 a10。这样,你就可以得到算法最终版本的全部协整。
Good luck!
好运!
#6
0
I needed a way to take a mixed string and create a string that could be sorted elsewhere, so that numbers sorted numerically and letters alphabetically. Based on answers above I created the following, which pads out all numbers in a way I can understand, wherever they appear in the string.
我需要一种方法来得到一个混合的字符串并创建一个可以在其他地方排序的字符串,以便数字按数字和字母按字母顺序排序。基于上面的答案,我创建了以下内容,它以我能理解的方式填充所有数字,无论它们在字符串中出现在哪里。
function padAllNumbers(strIn) {
// Used to create mixed strings that sort numerically as well as non-numerically
var patternDigits = /(\d+)/g; // This recognises digit/non-digit boundaries
var astrIn = strIn.split( patternDigits ); // we create an array of alternating digit/non-digit groups
var result = "";
for (var i=0;i<astrIn.length; i++) {
if (astrIn[i] != "") { // first and last elements can be "" and we don't want these padded out
if (isNaN(astrIn[i])) {
result += astrIn[i];
} else {
result += padOneNumberString("000000000",astrIn[i]);
}
}
}
return result;
}
function padOneNumberString(pad,strNum,left) {
// Pad out a string at left (or right)
if (typeof strNum === "undefined") return pad;
if (typeof left === "undefined") left = true;
var padLen = pad.length - (""+ strNum).length;
var padding = pad.substr(0,padLen);
return left? padding + strNum : strNum + padding;
}
#1
10
I think this does what you want
我想这就是你想要的
function sortArray(arr) {
var tempArr = [], n;
for (var i in arr) {
tempArr[i] = arr[i].match(/([^0-9]+)|([0-9]+)/g);
for (var j in tempArr[i]) {
if( ! isNaN(n = parseInt(tempArr[i][j])) ){
tempArr[i][j] = n;
}
}
}
tempArr.sort(function (x, y) {
for (var i in x) {
if (y.length < i || x[i] < y[i]) {
return -1; // x is longer
}
if (x[i] > y[i]) {
return 1;
}
}
return 0;
});
for (var i in tempArr) {
arr[i] = tempArr[i].join('');
}
return arr;
}
alert(
sortArray(["a1b3", "a10b11", "a10b2", "a9b2"]).join(",")
);
#2
5
Assuming what you want to do is just do a numeric sort by the digits in each array entry (ignoring the non-digits), you can use this:
假设您要做的是根据每个数组条目中的数字进行数字排序(忽略非数字),您可以使用以下方法:
function sortByDigits(array) {
var re = /\D/g;
array.sort(function(a, b) {
return(parseInt(a.replace(re, ""), 10) - parseInt(b.replace(re, ""), 10));
});
return(array);
}
It uses a custom sort function that removes the digits and converts to a number each time it's asked to do a comparison. You can see it work here: http://jsfiddle.net/jfriend00/t87m2/.
它使用自定义排序函数,每次请求进行比较时,它会删除数字并转换为数字。您可以在这里看到它的工作:http://jsfiddle.net/jfriend00/t87m2/。
If this isn't what you want, then please clarify as your question is not very clear on hwo the sort should actually work.
如果这不是你想要的,那么请澄清,因为你的问题不是很清楚的hwo类型应该是有效的。
#3
4
Use this compare function for sorting ..
使用这个比较函数进行排序。
function compareLists(a,b){
var alist = a.split(/(\d+)/), // split text on change from anything to digit and digit to anything
blist = b.split(/(\d+)/); // split text on change from anything to digit and digit to anything
alist.slice(-1) == '' ? alist.pop() : null; // remove the last element if empty
blist.slice(-1) == '' ? blist.pop() : null; // remove the last element if empty
for (var i = 0, len = alist.length; i < len;i++){
if (alist[i] != blist[i]){ // find the first non-equal part
if (alist[i].match(/\d/)) // if numeric
{
return +alist[i] - +blist[i]; // compare as number
} else {
return alist[i].localeCompare(blist[i]); // compare as string
}
}
}
return true;
}
Syntax
语法
var data = ["a1b3","a10b11","b10b2","a9b2","a1b20","a1c4"];
data.sort( compareLists );
alert(data);
demo at http://jsfiddle.net/h9Rqr/7/
演示http://jsfiddle.net/h9Rqr/7/
#4
1
Here's a more complete solution that sorts according to both letters and numbers in the strings
这里有一个更完整的解决方案,根据字符串中的字母和数字进行排序
function sort(list) {
var i, l, mi, ml, x;
// copy the original array
list = list.slice(0);
// split the strings, converting numeric (integer) parts to integers
// and leaving letters as strings
for( i = 0, l = list.length; i < l; i++ ) {
list[i] = list[i].match(/(\d+|[a-z]+)/g);
for( mi = 0, ml = list[i].length; mi < ml ; mi++ ) {
x = parseInt(list[i][mi], 10);
list[i][mi] = !!x || x === 0 ? x : list[i][mi];
}
}
// sort deeply, without comparing integers as strings
list = list.sort(function(a, b) {
var i = 0, l = a.length, res = 0;
while( res === 0 && i < l) {
if( a[i] !== b[i] ) {
res = a[i] < b[i] ? -1 : 1;
break;
}
// If you want to ignore the letters, and only sort by numbers
// use this instead:
//
// if( typeof a[i] === "number" && a[i] !== b[i] ) {
// res = a[i] < b[i] ? -1 : 1;
// break;
// }
i++;
}
return res;
});
// glue it together again
for( i = 0, l = list.length; i < l; i++ ) {
list[i] = list[i].join("");
}
return list;
}
#5
0
Sorting occurs from left to right unless you create a custom algorithm. Letters or digits are compared digits first then letters.
排序从左到右进行,除非您创建一个自定义算法。字母或数字首先是数字,然后是字母。
However, what you want to accomplish as per your own example (a1, a9, a10) WON'T EVER HAPPEN. That would require you knowing the data before hand and spliting the string in every possible way before applying the sorting.
但是,您希望按照自己的示例(a1、a9、a10)完成的任务不会发生。这将要求您事先知道数据,并在应用排序之前以各种可能的方式分割字符串。
One final alternative would be:
最后一种选择是:
a) break each and every string from left to right whenever is a change from letter to digit and vice versa; & b) then start the sorting on those groups from RIGHT-TO-LEFT. That will be a very demanding algorithm. Can be done!
a)每当从字母到数字发生变化时,将每个字符串从左到右分开,反之亦然;然后开始从右到左对这些组进行排序。这将是一个非常苛刻的算法。可以做!
Finally, if you are the GENERATOR of the original "text", you should consider NORMALIZING the output where a1 a9 a10 could be outputed as a01 a09 a10. This way you could have full cotnrol of the final version of the algorithm.
最后,如果您是原始“文本”的生成者,您应该考虑规范化输出,其中a1 a9 a10可以输出为a01 a09 a10。这样,你就可以得到算法最终版本的全部协整。
Good luck!
好运!
#6
0
I needed a way to take a mixed string and create a string that could be sorted elsewhere, so that numbers sorted numerically and letters alphabetically. Based on answers above I created the following, which pads out all numbers in a way I can understand, wherever they appear in the string.
我需要一种方法来得到一个混合的字符串并创建一个可以在其他地方排序的字符串,以便数字按数字和字母按字母顺序排序。基于上面的答案,我创建了以下内容,它以我能理解的方式填充所有数字,无论它们在字符串中出现在哪里。
function padAllNumbers(strIn) {
// Used to create mixed strings that sort numerically as well as non-numerically
var patternDigits = /(\d+)/g; // This recognises digit/non-digit boundaries
var astrIn = strIn.split( patternDigits ); // we create an array of alternating digit/non-digit groups
var result = "";
for (var i=0;i<astrIn.length; i++) {
if (astrIn[i] != "") { // first and last elements can be "" and we don't want these padded out
if (isNaN(astrIn[i])) {
result += astrIn[i];
} else {
result += padOneNumberString("000000000",astrIn[i]);
}
}
}
return result;
}
function padOneNumberString(pad,strNum,left) {
// Pad out a string at left (or right)
if (typeof strNum === "undefined") return pad;
if (typeof left === "undefined") left = true;
var padLen = pad.length - (""+ strNum).length;
var padding = pad.substr(0,padLen);
return left? padding + strNum : strNum + padding;
}