2011-11-12 51 views
8

Tôi muốn sắp xếp một chuỗi các chuỗi (trong javascript) sao cho các nhóm chữ số trong chuỗi được so sánh dưới dạng số nguyên không phải là chuỗi. Tôi không lo lắng về số điểm đã ký hoặc dấu phẩy động.cách sắp xếp chuỗi theo javascript số

ví dụ, kết quả nên ["a1b3","a9b2","a10b2","a10b11"] không ["a1b3","a10b11","a10b2","a9b2"]

Cách đơn giản nhất để làm điều này dường như được chia mỗi chuỗi trên ranh giới xung quanh nhóm chữ số. Có một mẫu mà tôi có thể chuyển tới String.split để phân chia ranh giới ký tự mà không xóa bất kỳ ký tự nào không?

"abc11def22ghi".split(/?/) = ["abc","11","def","22","ghi"];

Hoặc là có một cách khác để so sánh chuỗi không liên quan đến việc tách chúng lên, có lẽ bằng cách đệm tất cả các nhóm chữ số với số không hàng đầu vì vậy chúng có cùng độ dài?

"aa1bb" => "aa00000001bb", "aa10bb" => "aa00000010bb"

tôi đang làm việc với chuỗi tùy ý, không dây có một thỏa thuận cụ thể của nhóm chữ số.

Chỉnh sửa:

Tôi thích /(\d+)/ một lớp lót từ Gaby để chia mảng. Làm thế nào tương thích ngược là?

Các giải pháp phân tích cú pháp chuỗi một lần theo cách có thể được sử dụng để xây dựng lại bản gốc hiệu quả hơn nhiều so với chức năng so sánh này. Không có câu trả lời nào xử lý một số chuỗi bắt đầu bằng chữ số và các số khác thì không, nhưng điều đó sẽ dễ dàng đủ để khắc phục và không rõ ràng trong câu hỏi ban đầu.

["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(); 

kết quả: "!!,9,9.5,10,a3,a3b,a3b3,a3b20,a3b100,a20,a100,~~"

+0

Các phần không phải là số có luôn giống nhau không? Nếu không, liệu thuật toán sắp xếp có sắp xếp chúng theo thứ tự ASCII không? –

+1

Trong ví dụ của bạn, trích xuất 13, 92, 102, 1011? Hoặc là nó giống như 1.3, 9.2, 10.2, 10.11? Ý tôi là số đầu tiên quan trọng hơn hoặc là những chữ cái vừa bị bỏ qua? –

+0

... oh bạn vẫn muốn sắp xếp trên các số nguyên không, tôi nhận được nó ngay bây giờ ... –

Trả lời

9

Tôi nghĩ rằng đây không những gì bạn muốn

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(",") 
); 
+11

của hàm so sánh. –

5

Giả sử những gì bạn muốn làm là chỉ cần một loại số bằng các chữ số trong mỗi mục mảng (bỏ qua các phi chữ số), bạn có thể sử dụng này:

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

Nó sử dụng chức năng sắp xếp tùy chỉnh loại bỏ các chữ số và chuyển đổi thành một số mỗi lần được yêu cầu so sánh. Bạn có thể thấy nó hoạt động ở đây: http://jsfiddle.net/jfriend00/t87m2/.

Nếu đây không phải là những gì bạn muốn, thì vui lòng làm rõ vì câu hỏi của bạn không rõ ràng về việc sắp xếp thực sự có hiệu quả hay không.

+0

Tôi nghĩ rằng có thể có rắc rối nếu nó gặp một số không chì, không? I E. abc03def45 –

+0

@ Dr.Dredel - Việc sử dụng parseInt biến nó trở thành một kiểu số thuần túy. Các số 0 hàng đầu sẽ bị bỏ qua khi được chuyển thành một số thực như chúng cần. Tôi không thấy vấn đề gì cả. – jfriend00

+0

ah ... rất đúng ... nm –

1

Here's a more complete solution mà sắp xếp theo cả chữ và số trong chuỗi

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; 
} 
+0

Tôi nghĩ OP muốn bỏ qua các chữ số không và chỉ sắp xếp theo các chữ số. – jfriend00

+0

@ jfriend00: Hmmm ... bạn có thể đúng. Nếu vậy, bạn có thể thêm mệnh đề 'typeof a [i] ===" number "' vào hàm 'while'-loop – Flambino

0

Sorting xảy ra từ trái sang phải, trừ khi bạn tạo ra một thuật toán tùy chỉnh. Chữ cái hoặc chữ số được so sánh chữ số đầu tiên sau đó chữ cái.

Tuy nhiên, những gì bạn muốn thực hiện theo ví dụ của riêng bạn (a1, a9, a10) WON'T EVER HAPPEN. Điều đó sẽ yêu cầu bạn biết dữ liệu trước khi bàn tay và chia chuỗi theo mọi cách có thể trước khi áp dụng sắp xếp.

Một thay thế cuối cùng sẽ là:

a) phá vỡ từng chuỗi từ trái sang phải bất cứ khi nào có một sự thay đổi từ bức thư cho chữ số và ngược lại; & b) sau đó bắt đầu phân loại trên các nhóm đó từ RIGHT-TO-LEFT. Đó sẽ là một thuật toán rất khó. Có thể được thực hiện!

Cuối cùng, nếu bạn là GENERATOR của "văn bản gốc", bạn nên xem xét NORMALIZING đầu ra nơi a1 a9 a10 có thể được xuất ra là a01 a09 a10. Bằng cách này bạn có thể có đầy đủ cotnrol của phiên bản cuối cùng của thuật toán.

Chúc may mắn!

4

Sử dụng này so sánh chức năng để phân loại ..

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

Cú pháp

var data = ["a1b3","a10b11","b10b2","a9b2","a1b20","a1c4"]; 
data.sort(compareLists); 
alert(data); 

demo tạihttp://jsfiddle.net/h9Rqr/7/

0

Tôi cần một cách để lấy một chuỗi hỗn hợp và tạo một chuỗi có thể được sắp xếp ở nơi khác, để số được sắp xếp theo số và chữ cái theo thứ tự bảng chữ cái. Dựa trên các câu trả lời ở trên, tôi đã tạo ra những điều sau đây, giúp loại bỏ tất cả các con số theo cách tôi có thể hiểu được, bất cứ nơi nào chúng xuất hiện trong chuỗi.

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; 
} 
Các vấn đề liên quan