2012-05-16 12 views
12

sto cercando di evitare di scrivere il mio algoritmo di ordinamento per il seguente caso d'uso:come ordinare una collezione di oggetti in JavaScript senza convertirlo in un array

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

Ecco l'output della console:

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

Come si può vedere, con undes L'ordinamento del core. Sto perdendo i dati chiave. Questa struttura può diventare molto grande, quindi sto cercando di evitare cose come la conversione in un array e poi tornare alla collezione. C'è un modo per fare questo senza rotolare la mia funzione di ordinamento?

+2

Avatar è un dizionario e non ordinato dalla sua natura. Quindi, di cosa hai bisogno esattamente? Un'abilità per iterare su avatar in ordine? –

+0

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

risposta

26

tuo avatars non è una matrice, è solo un oggetto:

avatars = {}; 

quindi c'è no defined order for its elements:

La meccanica e l'ordine di enumerazione delle proprietà (passo 6.a nella il primo algoritmo, il passo 7.a nel secondo) non è specificato.

e 15.2.3.7 (e 15.2.3.14):

Se l'applicazione definisce uno specifico ordine di enumerazione per la for-in prospetto, che stesso ordine censimento deve essere utilizzato per ordinare gli elementi della lista in passaggio 3 di questo algoritmo.

È anche possibile controllare section 8.6 per verificare se è presente un riferimento sull'ordine delle proprietà in un oggetto. L'unico requisito per l'ordine delle proprietà degli oggetti è che se l'implementazione definisce un ordine ovunque, deve utilizzare lo stesso ordine ovunque ma questo è un grande se. La maggior parte delle implementazioni probabilmente usa l'ordine di inserzione per le chiavi di un oggetto ma non riesco a trovare nulla che le richieda (apprezzerei un commento se qualcuno può indicare qualcosa nelle specifiche che definiscono un particolare ordine delle chiavi di un oggetto).

Detto questo, Underscore di sortBy è fondamentalmente un Schwartzian Transform combinato con uno standard di JavaScript sort e sottolineatura di pluck per aprire il Trasformata di Schwartz involucri memo; pluck restituisce una matrice in modo che sortBy restituisca anche una matrice. Quindi, la tua chiamata finale _.keys(avatars) chiama effettivamente _.keys su un array; le chiavi di un array (le proprietà enumerabili di AKA) sono gli indici dell'array e quelli sono numeri interi consecutivi che iniziano da zero.

Si sta utilizzando la struttura dati errata. Se hai bisogno di un array sparse ma devi anche manipolarlo come un array (ad es.sorta di esso), allora si dovrebbe mettere gli indici all'interno degli oggetti e utilizzare una serie normale e pluck invece di 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')); 

Demo: http://jsfiddle.net/ambiguous/UCWL2/

Se hai bisogno anche un rapido accesso da idx allora si potrebbe impostare un oggetto parallelo per idx accesso diretto:

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

Poi avatars_by_idx fornisce l'accesso diretto che stai cercando. Ovviamente, dovresti mantenere avatars e avatars_by_idx sincronizzati ma ciò non è terribilmente difficile se li nascondi entrambi dietro ad un oggetto.

+0

grazie per la risposta dettagliata. Sfortunatamente ho bisogno di essere in grado di cercare rapidamente "record" nella collezione di avatar usando l'idx, quindi cambiare la struttura dei dati non è un'opzione. Forse sarebbe meglio creare una nuova lista usata per l'ordinamento ... – Rosco

+0

@Rosco: Se stai solo lavorando con i dati raw di 'avatars', usa l'array' avatars' come sopra il negozio principale e mantieni un oggetto separato che mappa 'idx' sugli oggetti nella matrice' avatars'. Questo oggetto extra 'avatars_by_idx' avrebbe lo stesso scopo di un indice in un database. –

+0

hmm - Stavo pensando il contrario: l'archivio dati sarebbe la raccolta di oggetti digitati su idx e l'array ordinato avrebbe contenuto solo l'idx ordinato in base al buddy_name. Ho dimenticato di menzionare che i nuovi avatar sono aggiunti alla struct dopo l'inizializzazione ... – Rosco

Problemi correlati