[英]how to sort strings in javascript numerically
我想對字符串數組(在 javascript 中)進行排序,以便將字符串中的數字組作為整數而不是字符串進行比較。 我不擔心有符號數或浮點數。
例如,結果應該是["a1b3","a9b2","a10b2","a10b11"]
而不是["a1b3","a10b11","a10b2","a9b2"]
最簡單的方法似乎是在數字組周圍的邊界上拆分每個字符串。 是否有一種模式可以傳遞給 String.split 以在不刪除任何字符的情況下拆分字符邊界?
"abc11def22ghi".split(/?/) = ["abc","11","def","22","ghi"];
或者是否有另一種方法來比較字符串而不涉及將它們拆分,也許通過用前導零填充所有數字組使它們具有相同的長度?
"aa1bb" => "aa00000001bb", "aa10bb" => "aa00000010bb"
我正在使用任意字符串,而不是具有特定數字組排列的字符串。
編輯:
我喜歡 Gaby 的/(\\d+)/
一個襯墊來分割數組。 那是如何向后兼容的?
以可用於重建原始字符串的方式解析字符串一次的解決方案比此比較函數更有效。 沒有一個答案處理一些以數字開頭的字符串,而另一些則不處理,但這很容易補救,並且在原始問題中並不明確。
["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();
結果: "!!,9,9.5,10,a3,a3b,a3b3,a3b20,a3b100,a20,a100,~~"
我認為這可以滿足您的要求
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(",")
);
另一種變體是使用帶有數字選項的Intl.Collator
實例:
var array = ["a100","a20","a3","a3b","a3b100","a3b20","a3b3","!!","~~","9","10","9.5"]; var collator = new Intl.Collator([], {numeric: true}); array.sort((a, b) => collator.compare(a, b)); console.log(array);
假設您想要做的只是按每個數組條目中的數字進行數字排序(忽略非數字),您可以使用:
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);
}
它使用自定義排序函數刪除數字並在每次要求進行比較時轉換為數字。 你可以在這里看到它的工作: http : //jsfiddle.net/jfriend00/t87m2/ 。
如果這不是您想要的,那么請澄清,因為您的問題不是很清楚排序應該如何實際工作。
使用此比較功能進行排序..
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;
}
句法
var data = ["a1b3","a10b11","b10b2","a9b2","a1b20","a1c4"];
data.sort( compareLists );
alert(data);
這是一個更完整的解決方案,它根據字符串中的字母和數字進行排序
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;
}
我需要一種方法來獲取混合字符串並創建一個可以在其他地方排序的字符串,以便數字按數字和字母順序排序。 根據上面的答案,我創建了以下內容,以我可以理解的方式填充所有數字,無論它們出現在字符串中的任何位置。
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;
}
除非您創建自定義算法,否則排序是從左到右進行的。 字母或數字先比較數字,然后比較字母。
但是,根據您自己的示例 (a1, a9, a10) 想要完成的操作永遠不會發生。 這將要求您事先了解數據並在應用排序之前以各種可能的方式拆分字符串。
最后一種選擇是:
a) 每當字母和數字發生變化時,從左到右斷開每個字符串,反之亦然; & b) 然后從右到左開始對這些組進行排序。 這將是一個非常苛刻的算法。 可以做到!
最后,如果您是原始“文本”的生成器,您應該考慮標准化輸出,其中 a1 a9 a10 可以輸出為 a01 a09 a10。 這樣你就可以完全控制算法的最終版本。
祝你好運!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.