2010-09-28 9 views
5

Ho una serie di oggetti Javascript che mi piacerebbe ordinare in modo incrociato da una proprietà che è sempre un numero intero positivo con una singola lettera opzionale a fine. Sto cercando una soluzione che funziona in almeno Firefox 3 e Internet Explorer 8. Il più vicino Sono venuto a tale funzione di ordinamento è la seguente:Javascript in IE8: come ordinare una matrice di oggetti con proprietà alfanumeriche

var arrayOfObjects = [{id: '1A', name: 'bar', size: 'big'}, {id: '1C', name: 'bar', size: 'small'}, {id: '1', name: 'foo', size: 'big'}, {id: '1F', name: 'bar', size: 'big'}, {id: '1E', name: 'bar', size: 'big'}, {id: '1B', name: 'bar', size: 'small'}, {id: '1D', name: 'bar', size: 'big'}, {id: '1G', name: 'foo', size: 'small'}, {id: '3', name: 'foo', size: 'small'}, {id: '23', name: 'foo', size: 'small'}, {id: '2', name: 'foo', size: 'small'}, {id: '1010', name: 'foo', size: 'small'}, {id: '23C', name: 'foo', size: 'small'}, {id: '15', name: 'foo', size: 'small'}] 

arrayOfObjects.sort(function(a, b){ 
    return (a.id < b.id ? -1 : a.id == b.id ? 0 : 1); 
}); 

Dopo essere stato così ordinato, stampare arrayOfObjects dà :

1, foo, grande
1010, foo, piccolo
15, foo, piccolo
1A, bar, grande
1B, bar, piccolo
1C, bar, piccolo
1D, bar, grande
1E, bar, grande
1F, bar, grande
1G, foo, piccolo
2, foo, piccolo
23, foo, piccolo
23C, foo, piccolo
3, foo , piccolo

Tuttavia, desidero arrayOfObjects stampare nel seguente ordine:

1, foo, grande
1A, bar, grande
1B , Bar, piccolo
1C, bar, piccolo
1D, bar, grande
1E, bar, grande
1F, bar, grande
1G, foo, piccolo
2, foo, piccolo
3, foo, piccolo
15, foo, piccolo
23, foo, piccolo
23C, foo, piccolo
1010, foo, piccolo

Dato che, come potrei risolvere il ab ove funzione in modo che gli oggetti vengano ordinati per numero come chiave primaria e lettera come chiave secondaria? Grazie in anticipo per qualsiasi aiuto.

risposta

3
arrayOfObjects.sort((function() { 
    var splitter = /^(\d+)([A-Z]*)/; 
    return function(a, b) { 
    a = a.id.match(splitter); b = b.id.match(splitter); 
    var anum = parseInt(a[1], 10), bnum = parseInt(b[1], 10); 
    if (anum === bnum) 
     return a[2] < b[2] ? -1 : a[2] > b[2] ? 1 : 0; 
    return anum - bnum; 
    } 
})()); 

l'idea è quella di dividere le chiavi nelle parti numeriche e stringa.

modifica (oops ottenuto il "match" chiamata indietro)

modificare nuovamente @ Ryan Tenney suggerisce saggiamente che la funzione esterna anonimo non è davvero necessario:

arrayOfObjects.sort(function(a, b) { 
    var splitter = /^(\d+)([A-Z]*)/; 
    a = a.id.match(splitter); b = b.id.match(splitter); 
    var anum = parseInt(a[1], 10), bnum = parseInt(b[1], 10); 
    if (anum === bnum) 
    return a[2] < b[2] ? -1 : a[2] > b[2] ? 1 : 0; 
    return anum - bnum;  
}); 

un po ' più semplice.

+0

Il letterale espressione regolare non aggiunge alcun costo per ogni iterazione. Faresti meglio a sbarazzarti della funzione di autoesecuzione esterna e dichiarare lo splitter all'interno della funzione interna. –

+0

Oltre a ciò, ottima risposta. È significativamente più conciso della risposta che stavo preparando ad offrire :) –

+0

Ho una cosa riguardo la ripetizione delle espressioni regex: non è tanto per le prestazioni quanto per la manutenzione. Forse una volta su cento ci proverò una regex al primo tentativo, quindi voglio ridurre al minimo il numero di volte che lo ripeto. Ovviamente avrei potuto semplicemente inserirlo come 'var' nel corpo della funzione; Non ci stavo pensando molto. – Pointy

0

Non è necessario analizzare il numero intero da una serie di digits-

Se le due stringhe di partita cifre, il valore non importa, si guarda a una possibile lettera.

Se le cifre non corrispondono, sottrarre una dall'altra costringe i numeri.

var rx=/^(\d+)(\D?)$/; 

    arrayOfObjects.sort(function(a, b){ 
     var id_a= a.id.match(rx), id_b= b.id.match(rx); 
     if(id_a[1]== id_b[1]){ 
      if(id_a[2]=== id_b[2]) return 0; 
      else{ 
       if(!id_a[2]) return -1; 
       if(!id_b[2]) return 1; 
       return id_a[2]> id_b[2]? 1: -1; 
      } 
     } 
     return id_a[1]-id_b[1]; 
    }); 
0

Qui è confrontare la funzione, con un po 'più di codice verbose e significativi nomi di variabili:

/** 
* Sort array ba numerical & alphabetical order ["1a", "2z", "2a", 99, 100] 
*/ 
function compare(a, b) { 

    var re = /(\d+)([^ ]?)/, numA, numB, charA, charB, 
     aMatches = re.exec(a), 
     bMatches = re.exec(b) ; 

    numA = aMatches[1] ? aMatches[1] : ''; //get the number part 
    charA = aMatches[2] ? aMatches[2] : ''; //get the char part 

    numB = bMatches[1] ? bMatches[1] : ''; 
    charB = bMatches[2] ? bMatches[2] : ''; 

    if (charA || charB){ //if one or both of the compare candidates have letter 
     if (numA==numB){ //only if number parts are equal 
      return charA.localeCompare(charB); // we compare letters 
     } 
    } 

    return numA - numB; // otherwise just compare numbers 
} 
Problemi correlati