Clasificación de valores con JavaScript

Las listas y tablas son a menudo la mejor manera de mostrar datos en la web; pero no debería tener que preocuparse por ordenar esa información manualmente. En el tutorial de hoy, harás un plugin jQuery que pondrá a todos tus patos en una fila con la facilidad de JavaScript!


Prefacio

Entonces, ¿cómo funciona exactamente la clasificación en JavaScript? No es demasiado complicado: cualquier objeto de matriz tiene un método de clasificación. Si no le pasa ningún parámetro, convertirá los objetos de la matriz en cadenas, los ordenará pseudo-alfabéticamente y los devolverá. Por lo general, esto es terrible; Considere ordenar los números del 0 al 10 alfabéticamente. Obtendrías esto: [0, 1, 10, 2, 3, 4, 5, 6, 7, 8, 9]. Afortunadamente, podemos pasar una función al método de clasificación. Esa función debe tomar dos parámetros (los dos elementos que se compararán): luego, devolverá 0 si son iguales, un número negativo si el primer parámetro tiene prioridad, o un número positivo del segundo parámetro debería aparecer primero. Así que los números son en realidad lo más simple de ordenar "manualmente":

 numberArray.sort (función (a, b) return a - b);

Obviamente, esto devolverá 0 si los números son iguales, un número negativo si una Debería ser el primero, y un número positivo si segundo debería ser el primero.

Vamos a ver cómo se ordenan varios tipos diferentes de datos, algunos en múltiples formatos; pero todo esto será mucho más útil si lo envolvemos en un complemento jQuery, así que comencemos configurando ese shell.!

El shell plugin

Si no está familiarizado con la escritura de complementos de jQuery, consulte el Screencast de Jeffrey Way "¿Aún no puede crear un complemento de jQuery?" ¡Te pondrá al día en poco tiempo si te sientes cómodo con jQuery! (Confesión verdadera: en realidad nunca había escrito un plugin hasta que hice este).

Configuraremos nuestro complemento, llamado datasort, de esta manera: le pasaremos una serie de elementos para ordenar; podemos especificar cuatro parámetros.

  • tipo de datos (el tipo de datos que estás ordenando)
  • sortElement (el elemento secundario que desea ordenar, si lo desea)
  • sortAttr (el atributo que desea ordenar, si lo desea)
  • marcha atrás (la dirección en la que deben clasificar)

Por lo tanto, una llamada completamente modificada a nuestro complemento podría tener este aspecto:

 $ ('ul.names li) .datasort (datatype:' alpha ', sortElement:' span.first ', sortAttr:' rel ', reverse: true);

Aquí está la cáscara del plugin:

 (function ($) $ .fn.datasort = function (options) var defaults = // establezca el tipo de datos del parámetro predeterminado: 'alpha', sortElement: false, sortAttr: false, reverse: false, // combine los parámetros predeterminados y del usuario, anulando la configuración por defecto = $ .extend (, por defecto, opciones), tipos de datos = , base = , that = esto; if (typeof settings.datatype === 'string')  that.sort (datatypes [settings.datatype]); if (typeof settings.datatype === 'function') that.sort (settings.datatype); if (settings.reverse) that = $ ($. makeArray (this) .reverse ()); $ .each (that, function (index, element) that.parent (). append (element););;) (jQuery);

Así es como funcionará: configuraremos todas las variables al principio. Luego, si el parámetro datatype es una cadena, encontraremos la función de clasificación correspondiente en el objeto datatypes y la ordenaremos; Si el parámetro del tipo de datos es una función, lo ordenaremos. Finalmente, si la configuración inversa se establece en verdadero, invertiremos el orden de los elementos ordenados (dado que los objetos jQuery no son verdaderos arreglos de JavaScript, la función inversa no funcionará en ellos, por lo que podemos usar $ .makeArray ( ) para convertirlo en uno; luego, una vez que se invierte, ¡lo re-buscamos!.

Poniendo un poco más de fundamento

En el nivel más bajo, puede ordenar casi cualquier tipo de datos de una de las dos maneras siguientes: los llamaremos alfabéticamente y numéricamente. Vamos a crear estas dos funciones como propiedades de su objeto base.

 base = alfa: función (a, b) a = a.toUpperCase (); b = b.toUpperCase (); retorno (un < b) ? -1 : (a > b): 1: 0; // operador ternario: condición? returnIfTrue: returnIfFalse, number: function (a, b) a = parseFloat (a); b = parseFloat (b); devuelve a - b; ,

Bastante simple, ¿eh? Simplemente normalice los dos valores, compare y regrese. La parte difícil es analizar los datos que queremos enviar a estas funciones; eso es lo que haremos ahora. Sin embargo, hay una cosa más.

Al ordenar los elementos de la matriz, es posible que no queramos clasificarlos simplemente por el texto del propio elemento. Los parámetros sortElement y sortAttr de nuestro complemento son para este fin. Por ejemplo, es probable que queramos ordenar las filas de la tabla en función de una determinada columna de celdas de la tabla. En ese caso, usaríamos $ ('table tr'). Datasort (sortElement: 'td.price'). O quizás queremos ordenar una lista de imágenes por sus atributos alt: $ ('ul li'). Datasort (sortElement: 'img', sortAttr: 'alt'). Debido a todo esto, necesitamos agregar una función más a nuestro objeto base:

 base = alfa: función (a, b) …, número: función (a, b) …, extraer: función (a, b) var get = función (i) var o = $ (i ); if (settings.sortElement) o = o.children (settings.sortElement);  if (settings.sortAttr) o = o.attr (settings.sortAttr);  else o = o.text ();  devolver o; ; devuelve a: get (a), b: get (b); ,

Puede parecer complicado, pero no lo es. Simplemente creamos un objeto jQuery con cada elemento; Si se establece sortElement, usamos el método children () para obtener los elementos correctos. Entonces, si se establece un sortAttr, obtenemos su valor; Si no, obtenemos el texto del elemento. Hemos establecido todo esto en una función interna y hemos devuelto un objeto con dos propiedades; estas propiedades son los valores que debemos analizar y enviar a la función de clasificación base apropiada.

Esto probablemente parecía mucho trabajo de preparación, pero lo que realmente estábamos haciendo es abstraer la mayor cantidad de código posible. De esta manera, tendrán un código de repetición mucho menor, ya que las acciones importantes se han agrupado como funciones.

Ordenar palabras y números

Finalmente estamos aquí: ¡la parte divertida! Comenzaremos por construir dos funciones simples para nuestro objeto datatypes. Estos simplemente pasarán los valores a base.extract () y luego pasarán esos valores de retorno a la clase de clasificación apropiada.

 tipos de datos = alfa: función (a, b) var o = base.extract (a, b); devuelve base.alpha (o.a, o.b); , número: función (a, b) var o = base.extract (a, b); para (var e in) o [e] = o [e] .replace (/ [$]? (-? \ d +.? \ d +) /, '\ $ 1');  devuelve base.number (o.a, o.b); ,

Nuestro clasificador alfabético debe ser obvio. El clasificador de números hace un poco más: antes de pasar los valores extraídos, elimina un signo de dólar en el frente. He mantenido esta expresión regular simple, pero podría analizar muchos formatos de números diferentes aquí si quisiera ser complejo. Vamos a probar nuestro plugin en evolución; crear una página html básica:

     Clasificación de datos    
Nombre de pila Apellido
Jeffrey Camino
Sean Hodge
Adán Molinero
Ian Yates
Adrián Tratar
Caleb Aylsworth
  • 4,09
  • 4.10
  • 67.8
  • 100
  • -98
  • 67.7
  • 23
  • $ 299.66
  • $ 299.57
  • $ 0.14
  • $ 80.00

He incluido una tabla y dos listas (y las he diseñado brevemente). Tome nota de nuestras llamadas a los complementos: estamos usando el tipo de datos predeterminado para la tabla, pero ordenando por las celdas de la tabla con una clase de último; intenta cambiar esto a 'td.first'. Luego, ordenamos las listas numéricamente, y revertimos una de ellas. Aquí está la prueba de nuestros trabajos:

Bastante bien, pero esos eran valores relativamente simples; ¿Qué pasa si queremos poder ordenar múltiples formatos para un tipo?

Fechas de clasificación

Hay varias formas diferentes de escribir fechas, lo que hace que sea bastante difícil analizarlas para clasificarlas. Sin embargo, podemos cubrir la mayoría de ellos con esto:

 fecha: función (a, b) var o = base.extract (a, b); para (var e in) o [e] = o [e] .replace (/ - / g, ") .replace (/ enero | jan / i, '01') .replace (/ febrero | feb / i , '02') .replace (/ march | mar / i, '03') .replace (/ april | apr / i, '04') .replace (/ may / i, '05') .replace (/ june | jun / i, '06') .replace (/ july | jul / i, '07') .replace (/ agosto | aug / i, '08') .replace (/ september | sept | sep / i, ' 09 ') .replace (/ october | oct / i,' 10 ') .replace (/ november | nov / i,' 11 ') .replace (/ december | dec / i,' 12 ') .replace (/ ( \ d 2) (\ d 2), (\ d 4) /, '\ $ 3 \ $ 1 \ $ 2') .replace (/ (\ d 2) \ / (\ d 2 ) \ / (\ d 4) /, '\ $ 3 \ $ 2 \ $ 1'); return base.number (oa, ob);, 

Entonces que hacemos aqui? Primero, aquí está la lógica: si todas las fechas tienen el formato AAAAMMDD, se ordenarán correctamente con la clasificación numérica. Nuestro analizador puede ordenar los siguientes formatos de fecha:

  • YYYY-MM-DD
  • AAAAMMDD
  • DD / MM / YYYY
  • mes DD, YYYY

Primero, eliminamos nuestros guiones, lo que dejará a YYYY-MM-DD listo para el análisis. Luego, reemplazamos el nombre o la abreviatura de cada mes con su valor numérico. Finalmente, tenemos que reorganizar los números para DD / MM / YYY y el mes DD, YYYY. Eso es lo que hacen las dos últimas expresiones. Para intentarlo, pega esta lista en nuestro HTML:

 
  • 2009-10-06
  • 25 de septiembre de 1995
  • 1990-06-18
  • 20100131
  • 18 de junio de 2009
  • 11/02/1993
  • 15941219
  • 1965-08-05
  • 1425-12-25

Y llámalo con esto:

 $ ('ul.date li'). datasort (datatype: 'date');

¿Es este un analizador de citas perfecto? No de ninguna manera; no podemos clasificar DD / MM / YY, porque no hay manera de saber en qué siglo está. Además, no podemos decir la diferencia entre DD / MM / YY y MM / DD / YY, así que solo tenemos que elige uno.

Tiempo de clasificación

La clasificación de los valores de tiempo debe ser uno de los más difíciles de clasificar: debemos ser capaces de aceptar 12 horas, 24 horas y valores con o sin etiquetas AM / PM y segundos. Creo que es más fácil ordenar el tiempo alfabéticamente, a pesar de que son todos los números. ¿Por qué? Considere estas dos marcas de tiempo: 00:15:37 y 12:15. El primero debería venir primero, pero si los clasificamos por número, se analizarán como flotadores y terminarán como 1537 y 1215. Ahora, el segundo valor será lo primero. Además, al ordenar alfabéticamente, no tenemos que eliminar los dos puntos (parseFloat () se ahogaría con ellos). Así que aquí está cómo se hace..

 tiempo: función (a, b) var o = base.extract (a, b), tarde = /^(.+) PM $ / i; para (var e in) o [e] = o [e] .split (':'); var last = o [e] .length - 1; if (afternoon.test (o [e] [last])) o [e] [0] = (parseInt (o [e] [0]) + 12) .toString (); o [e] [último] = o [e] [último] .replace (tarde, '\ $ 1');  if (parseInt (o [e] [0]) < 10 && o[e][0].length === 1)  o[e][0] = '0' + o[e][0];  o[e][last] = o[e][last].replace(/^(.+) AM$/i, '\$1'); o[e] = o[e].join(");  return base.alpha(o.a, o.b); 

Vayamos a través de esta línea por línea.

 var o = base.extract (a, b), tarde = /^(.+) PM $ / i;

Comenzamos con nuestras variables: nuestros valores extraídos y una expresión regular para verificar la etiqueta de PM.

 para (var e in) o [e] = o [e] .split (':'); var last = o [e] .length - 1; if (afternoon.test (o [e] [last])) o [e] [0] = (parseInt (o [e] [0]) + 12) .toString (); o [e] [último] = o [e] [último] .replace (tarde, '\ $ 1'); 

A continuación, comenzaremos un bucle for, repasando cada uno de los valores que estamos ordenando; Primero, lo dividimos en una matriz en los dos puntos. Creamos una manera fácil de llegar a los últimos elementos de la matriz: nuestra variable 'última'. Luego, probamos nuestra expresión regular de PM en el último elemento de nuestra matriz; si devuelve true, este valor tiene la etiqueta PM. Por lo tanto, agregaremos 12 al primer elemento de nuestra matriz, que será el valor de la hora; Hacemos esto porque necesitamos que todos los valores estén formateados en un tiempo de 24 horas. (Tenga en cuenta que para hacer esto, debemos convertirlo en un número, agregar 12 y luego volver a convertirlo en una cadena). Finalmente, usamos la expresión regular PM nuevamente para eliminar esa etiqueta del último elemento de la matriz.

 if (parseInt (o [e] [0]) < 10 && o[e][0].length === 1)  o[e][0] = '0' + o[e][0];  o[e][last] = o[e][last].replace(/^(.+) AM$/i, '\$1'); o[e] = o[e].join(");  return base.alpha(o.a, o.b);

En este último fragmento, verificamos el valor de la hora para dos condiciones: ¿es menor que 10? ¿Y la cadena tiene un solo carácter? Esto es importante porque un valor como 08 se analizará como 8 y será menor que 10; pero estamos tratando de ver si necesitamos agregar un cero al frente. Si la cadena tiene solo un carácter, entonces agregamos el cero, entonces 3 se convierte en 03. Esto mantendrá las cosas en orden!

Antes de unirnos a la matriz, eliminamos cualquier etiqueta de AM. Así que ahora esto ...

 
  • 1:15:47
  • 3:45 PM
  • 12:00:17
  • 06:56
  • 19:39
  • 4:32 a.m.
  • 00:15:36

... se puede ordenar con esto ...

 $ ('ul.time li'). datasort (datatype: 'time'); 

¡Y hemos terminado! He aquí los frutos de nuestro trabajo:

Más valores aleatorios

Hemos configurado nuestro complemento jQuery para que los usuarios puedan pasar las funciones de clasificación como el parámetro de tipo de datos. Esto nos permite extender fácilmente el complemento, aunque no tenemos acceso a la 'clase' base desde la llamada del complemento. Podemos escribir fácilmente una función para ordenar las clasificaciones psudeo:

 $ ('ul.rating li'). datasort (datatype: function (a, b) var o = a: $ (a) .text (), b: $ (b) .text () para ( var e in o) o [e] = o [e] .replace (/ poor / i, 0) .replace (/ satisfactoria / i, 1) .replace (/ good / i, 2) .replace (/ excellent / i, 3); return oa - ob;);

Esto utiliza las expresiones regulares más simples posibles para ordenar una lista como esta:

 
  • Bueno
  • Excelente
  • Pobre
  • Satisfactorio

Eso es un envoltorio!

Ahora lo sabe: ordenar valores en JavaScript realmente no es tan difícil como podría haber pensado. Puedes imaginar que esto sea útil para ordenar una tabla, con algo como esto:

 $ ('table # myTable thead th'). toggle (function () var $ this = $ (this); $ ('table # myTable tbody tr'). datasort (datatype: $ this.attr ('rel' ), sortElement: 'td.' + $ this.attr ('class'));, function () var $ this = $ (this); $ ('table # myTable tbody tr'). datasort ( tipo de datos: $ this.attr ('rel'), sortElement: 'td.' + $ this.attr ('class'), reverse: true);); 

(¡Trate de reemplazar el código jQuery para la tabla en el primer ejemplo con esto!)

Por supuesto, podríamos mejorar mucho este plugin; por ejemplo, podríamos hacer que compruebe el rel atributo para un tipo de datos si no se proporciona uno como parámetro, y predeterminado a alfa si no hay rel. Pero eso aparte de la clasificación..

En resumen, para clasificar con JavaScipt, seguimos estos pasos:

  1. Determine los diferentes formatos que desea ordenar.
  2. Decide qué formato quieres ordenar.
  3. Ordene la matriz de elementos con el método sort (), pasando una función que convertirá los dos elementos al formato deseado antes de compararlos.

¿Tiene un tipo de datos para agregar a nuestro complemento? ¿Tienes una mejor manera de clasificar uno de estos? Vamos a escucharlo en los comentarios.!

  • Síganos en Twitter o suscríbase a Nettuts + RSS Feed para obtener los mejores tutoriales de desarrollo web en la web..