2012-05-16 26 views
12

que estoy tratando de evitar la escritura de mi propio algoritmo de clasificación para el siguiente caso de uso:Cómo ordenar una colección de objetos en JavaScript sin necesidad de convertirlo en una matriz

avatars = {}; 
avatars[102] = {userInfo: {buddy_name: 'Avatar102', is_online: 1}}; 
avatars[100] = {userInfo: {buddy_name: 'Avatar100', is_online: 1}}; 
avatars[101] = {userInfo: {buddy_name: 'Avatar101', is_online: 1}}; 

console.log(_.keys(avatars)); 
avatars = _.sortBy(avatars, function(avatar) {return avatar.userInfo.buddy_name.toLowerCase();}); 
console.log(_.keys(avatars)); 

Aquí está la salida de la consola:

  • [ "102", "100", "101"]
  • [ "0", "1", "2"]

Como se puede ver, con Undes clasificación del núcleoPorque estoy perdiendo los datos clave. Esta estructura puede ser muy grande, así que estoy tratando de evitar cosas como la conversión a una matriz y luego volver a la colección. ¿Hay alguna forma de hacerlo sin tener que implementar mi propia función de clasificación?

+2

Avatars es un diccionario y no está ordenado por su naturaleza. Entonces, ¿qué necesitas exactamente? ¿Una habilidad para iterar sobre avatares en orden? –

+0

http://jsfiddle.net/zL9GD/2/ –

Respuesta

26

Su avatars no es una matriz, es sólo un objeto:

avatars = {}; 

por lo que no es no defined order for its elements:

La mecánica y el orden de la enumeración de las propiedades (paso 6.a en el primer algoritmo, paso 7.a en el segundo) no se especifica.

y 15.2.3.7 (y 15.2.3.14):

Si una implementación define un orden específico de enumeración para el para-en la declaración, ese mismo orden de enumeración debe ser utilizado para ordenar los elementos de la lista en el paso 3 de este algoritmo

También puede consultar section 8.6 para ver si hay alguna mención sobre el orden de las propiedades en un objeto. El único requisito para ordenar las propiedades del objeto es que si la implementación define un orden en cualquier lugar, debe usar el mismo orden en todas partes, pero ese es un gran si. La mayoría de las implementaciones probablemente usan el orden de inserción para las claves de un objeto, pero no puedo encontrar nada que lo requiera (agradecería un comentario si alguien puede señalar algo en las especificaciones que definen un orden particular de las claves de un objeto).

Dicho esto, Subrayado de sortBy es básicamente un Schwartzian Transform combinado con un estándar de JavaScript sort y subrayado de pluck a desenvolver el Schwartzian Transform envoltorios de notas; pluck devuelve una matriz para que sortBy también devuelva una matriz. Por lo tanto, su llamada final _.keys(avatars) está realmente llamando al _.keys en una matriz; las claves de una matriz (propiedades enumerables AKA) son los índices de la matriz y son enteros consecutivos que comienzan en cero.

Está utilizando una estructura de datos incorrecta. Si necesita una matriz dispersa, pero también necesita manipularla como una matriz (es decir,tipo), entonces usted debe poner los índices dentro de los objetos y el uso de una matriz normal y pluck en lugar de keys:

var avatars = [ 
    {idx: 102, userInfo: {buddy_name: 'Avatar102', is_online: 1}}, 
    {idx: 100, userInfo: {buddy_name: 'Avatar100', is_online: 1}}, 
    {idx: 101, userInfo: {buddy_name: 'Avatar101', is_online: 1}} 
]; 
console.log(_(avatars).pluck('idx')); 
avatars = _(avatars).sortBy(function(avatar) { 
    return avatar.userInfo.buddy_name.toLowerCase(); 
}); 
console.log(_(avatars).pluck('idx')); 

Demostración: http://jsfiddle.net/ambiguous/UCWL2/

Si también necesita un rápido acceso por idx entonces se podría establecer un objeto paralelo para idx acceso directo:

var avatars_by_idx = { }; 
for(var i = 0; i < avatars.length; ++i) 
    avatars_by_idx[avatars[i].idx] = avatars[i]; 

Entonces avatars_by_idx proporciona el acceso directo que está buscando. Por supuesto, debe mantener sincronizados avatars y avatars_by_idx, pero eso no es terriblemente difícil si los oculta detrás de un objeto.

+0

gracias por la respuesta detallada. Lamentablemente, necesito poder buscar rápidamente "registros" en la colección de avatares usando el idx, por lo que cambiar la estructura de datos no es una opción. Tal vez sería mejor crear una nueva lista utilizada para la clasificación ... – Rosco

+0

@Rosco: si solo estás trabajando con los datos de los avatares en bruto, utiliza la matriz 'avatares' como la tienda principal y conserva un objeto separado que asigna el 'idx' a los objetos en la matriz' avatars'. Este objeto 'avatars_by_idx' adicional serviría para el mismo propósito que un índice en una base de datos. –

+0

hmm - Estaba pensando lo contrario: el almacén de datos sería la colección de objetos codificados en idx, y la matriz ordenada solo contendría el orden idx basado en el buddy_name. Olvidé mencionar que los nuevos avatares se agregan a la estructura después de la inicialización ... – Rosco

Cuestiones relacionadas