Array.sort en detalle

Este método del object Array ordena los elementos del objeto actual segun un criterio dado. Por defecto, el orden de los elementos es definido por una simple comparación lexicográfica* de los mismos, siendo que cada elemento se coerce a string para luego ser comparado.

*Esto es en orden de diccionario, por ejemplo ‘a’ < ‘b’ < ‘c’. Los símbolos también cuentan, ejemplo ‘-‘ < ‘[‘ < ‘a’.

En el caso de las listas numericas esto puede significar un orden no correcto:

// El resultado del sort es un array
// [1, 10, 2, 3, 4]
[4,3,2,1,10].sort();

De igual manera sucede con otros tipos de objetos:

// Se ordena lexicográficamente por su coerción a string
// [[], RegExp, Object {}, function()]
[function() {}, /./, {}, []].sort();

Por suerte, para casos donde se requiera un ordenamiento más específico, podemos hacer uso del único argumento que recibe el método sort, que es ni más ni menos que una función. La función en cuestión recibe dos argumentos, que son dos elementos a comparar y debe devolver un valor numerico acorde a la comparación realizada entre ambos elementos (algo parecido a lo que provee Java mediante la interfaz Comparable):

Para un par de elementos [a, b] debe devolver

  • Un número negativo en caso de que se cumpla a < b (es decir, a tendrá un índice menor que b).
  • Cero en caso de que se cumpla a = b.
  • Un número positivo en caso de que se cumpla a > b (es decir, b tendrá un índice menor que a).

De esta manera, podes ordenar listas de objetos con un criterio puntual. Suponiendo que tenemos datos de futbolistas, podemos utilizar distintos criterios de ordenamiento.

// Estadisticas de la temporada 2010-2011 de
// la liga española
// *Datos extraidos de ESPN
var players = [
	{
		player: 'Cristiano Ronaldo',
		goals: 40,
		assists: 10,
		team: {
			name: 'Real Madrid',
			pos: 2
		}
	},
	{
		player: 'Lionel Messi',
		goals: 31,
		assists: 18,
		team: {
			name: 'Barcelona',
			pos: 1
		}
	},
	{
		player: 'Sergio Agüero',
		goals: 20,
		assists: 2,
		team: {
			name: 'Atlético Madrid',
			pos: 7
		}
	},
	{
		player: 'Alvaro Negredo',
		goals: 20,
		assists: 5,
		team: {
			name: 'Sevilla',
			pos: 5
		}
	}
];

Obtenemos la lista de goleadores, que básicamente consiste en ordenar por goles:

// Tabla de goleadores, ordenamos por goles
var topscorers = players.sort(function(one, another) {
	// Si tienen la misma cantidad de goles
	// no se modifica
	if(one.goals == another.goals) {
		return 0;
	}	

	return one.goals > another.goals ? -1 : 1;
});

topscorers; // Ronaldo, Messi, Aguero, Negredo

En este caso se puede refinar el ordenamiento, siendo que en caso de que tengan la misma cantidad de goles tome en consideración las asistencias de cada jugador:

// Tabla de goleadores, ordenamos por goles
// En caso de empates contabilizamos las asistencias
var topscorers = players.sort(function(one, another) {
	if(one.goals != another.goals) {
		// En este caso simplificamos la operación
		// utilizando una resta
		return another.goals - one.goals;
	}

	return another.assists - one.assists;
});

topscorers; // Ronaldo, Messi, Negredo, Aguero

De similar manera, se puede aplicar el ordenamiento a listas heterogéneas de manera nativa gracias al uso del método sort. Como nota final, hay que advertir sobre las pequeñas inconsistencias que existen en torno a este método.

Extraído de la documentación de Mozilla con respecto al ordenamiento:

If compareFunction(a, b) returns 0, leave a and b unchanged with respect to each other, but sorted with respect to all different elements. Note: the ECMAscript standard does not guarantee this behaviour, and thus not all browsers (e.g. Mozilla versions dating back to at least 2003) respect this.

Por otro lado, hay que tener en cuenta que Internet Explorer puede fallar en situaciones en las cuales se modifiquen los argumentos que recibe la función de sort. Para más información recomiendo leer el artículo linkeado a continuación.

Leer más


Shortlink: http://goo.gl/sNDT1




Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Comment

You may use these tags : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>