2012-03-20 18 views
19

con un array come questo:Come si ordina una matrice con coffeescript?

users = [ 
    { id: 1, fname: 'Fred', lname: 'Flinstone', state: 'CA' }, 
    { id: 2, fname: 'George', lname: 'Winston', state: 'FL' }, 
    { id: 3, fname: 'Luke', lname: 'Skywalker', state: 'CA' } 
] 

e si desidera ordinare per cognome con CoffeeScript, si può fare questo:

users.sort (a,b) -> 
    return if a.lname.toUpperCase() >= b.lname.toUpperCase() then 1 else -1 

Ho provato ad utilizzare una funzione come questa:

sortBy = (field, reverse, primer) -> 
    key = (x) -> 
     return if primer? then primer x[field] else x[field] 
    return (a,b) -> 
     A = key a 
     B = key b 
     return (A < B ? -1 : (A > B ? 1 : 0)) * [1,-1][+!!reverse] 

invocato in questo modo:

users.sort sortBy "lname", false, (a) -> 
    return a.toUpperCase() 

ma quello non ha ordinato correttamente la matrice.

C'è un modo per ordinare da più di 1 campo, cioè ordinare prima per stato e poi per cognome? Speravo di migliorare la funzione "sortBy" sopra e aggiungere la possibilità di ordinare almeno 2 campi.

+2

Che genere di cosa potrebbe essere "migliore" di quello? (In realtà io userei '<=' e non '<' per mantenere stabile l'ordinamento.) – Pointy

+3

Questo non è JSON. –

+0

Qui puoi utilizzare l'operatore ternario: 'return a.lname.toUpperCase()> b.lname.toUpperCase()? 1: -1' –

risposta

20

C'è un modo più semplice. Basta riutilizzare la funzione di ordinamento generalizzato, e concatenare utilizzando ||:

sortBy = (key, a, b, r) -> 
    r = if r then 1 else -1 
    return -1*r if a[key] > b[key] 
    return +1*r if a[key] < b[key] 
    return 0 

users.sort (a,b) -> 
    sortBy('id', a, b, true) or 
    sortBy('lname', a, b) or 
    sortBy('fname', a, b) 

Le funzioni sono a buon mercato. È quindi possibile costruire un'astrazione per questo:

sortByMultiple = (a, b, keys) -> 
    return r if (r = sortBy key, a, b) for key in keys 
    return 0 

users.sort (a,b) -> sortByMultiple a, b, ['id', 'lname', 'fname'] 

Ma poi si perde la possibilità di impostare ordine o altri parametri per ciascuna di esse.

+0

che sono davvero chiari. Sto cercando di capire come funziona il "o" con il concatenamento delle funzioni. È perché si sposta solo alla funzione nextyBy successiva se il precedente restituisce '0'? O forse un altro modo per dirlo è che manterrà l'ordinamento finché la prima chiave non sarà soddisfatta (cioè '0') e poi passerà alla successiva? – jiy

+0

Testato concatenando le funzioni sortBy con o - funziona alla grande! Lanciare sortByMultiple nel mix non ha avuto successo, tuttavia, nulla è stato ordinato correttamente. Grazie per la risposta molto utile! – jiy

+0

@jiy sì, è praticamente tutto. Continua fino a quando uno dei criteri restituisce un valore diverso da zero. –

15

In alternativa, si potrebbe voler considerare l'utilizzo Underscore s' sortBy in modo che non c'è bisogno di implementare da soli:

_(users).sortBy (u) -> [u.state, u.lname.toUpperCase()] 
+0

Grazie! Sembra estremamente promettente. Esattamente quello che stavo cercando – jiy

+0

I link nella tua risposta non esistono più http://underscorejs.org/ e http://underscorejs.org/#sortBy ci sono i nuovi link –

3

Questo è qualcosa che pensavo avrebbe implementato di default quando si utilizza lodash, ma non lo è.

Quindi eccoci qui!

sortByLowercase: (collection, key) -> 
    collection.sort (a, b) -> 
     [av, bv] = [a[key], b[key]] 
     [av, bv] = [av.toLowerCase(), bv.toLowerCase()] 
     if av >= bv then 1 else if av <= bv then -1 else 0 

sortByLowercase(users,'lname') 

Sulla base di un esempio più generico ho trovato here

Problemi correlati