2010-09-28 19 views
5

Tengo una matriz de objetos Javascript que me gustaría cruzar-compatiblemente ordenar por una propiedad que siempre es un entero positivo con una sola letra opcional en el fin. Estoy buscando una solución que funciona en al menos Firefox 3 e Internet Explorer 8. Lo más cerca que he llegado a tal función de clasificación es la siguiente:Javascript en IE8: cómo ordenar una matriz de objetos por propiedad alfanumérica

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

Después de ser tan ordenados, la impresión de arrayOfObjects da :

1, foo, grande
1010, foo, pequeño
15, foo, pequeño
1A, bar, gran
1B, bar, pequeño
1C, bar, pequeño
1D, bar, gran
1E, bar, gran
1F, bar, gran
1G, foo, pequeño
2, foo, pequeño
23, foo, pequeño
23C, foo, pequeño
3, foo , pequeña

Sin embargo, me gustaría arrayOfObjects de imprimir en el orden siguiente:

1, foo, gran
1A, bar, gran
1B , Bar, pequeño
1C, bar, pequeño
1D, bar, gran
1E, bar, gran
1F, bar, gran
1G, foo, pequeño
2, foo, pequeño
3, foo, pequeña
15, foo, pequeña
23, foo, pequeña
23C, foo, pequeña
1010, foo, pequeña

Teniendo en cuenta que, ¿cómo podría solucionar el ab ¿Funciona de modo que los objetos se clasifiquen por número como clave primaria y letra como clave secundaria? Gracias de antemano por cualquier ayuda.

Respuesta

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

la idea es dividir las llaves en las partes numéricas y de cuerda.

edición (vaya consiguió el "partido" llamar al revés)

editar nuevamente @Ryan Tenney prudencia sugiere que la función externa anónimo no es realmente necesario:

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 poco más simple.

+0

El literal de expresiones regulares no agrega ningún costo para cada iteración. Sería mejor que se deshaga de la función de autoejecución externa y declare el divisor dentro de la función interna. –

+0

Además de eso, gran respuesta. Es significativamente más conciso que la respuesta que me estaba preparando para ofrecer :) –

+0

No me importa repetir las expresiones regulares, no es tanto por el rendimiento como por el mantenimiento. Quizás una vez en cien intentos obtendré una expresión regular justo en el primer intento, por lo que quiero minimizar el número de veces que lo repito. Por supuesto, podría haberlo ingresado como una 'var' en el cuerpo de la función; No estaba pensando mucho sobre eso. – Pointy

0

No es necesario analizar el número entero de una serie de digits-

Si las dos cadenas de dígitos coinciden, el valor no importa, se mira a una posible carta.

Si los dígitos no coinciden, restar uno de los otros coacciona los números.

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

aquí es función de comparación, con un poco más de código detallado y nombres de variables significativas:

/** 
* 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 
} 
Cuestiones relacionadas