2012-03-20 15 views
19

con una serie como esta:¿Cómo puedo ordenar una matriz 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' } 
] 

y desea ordenar por apellido con CoffeeScript, usted puede hacer esto:

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

He intentado utilizar una función como esta:

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] 

que se invoca así:

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

pero eso no ordenó la matriz correctamente.

¿Hay alguna manera de ordenar por más de 1 campo, es decir, ordenar primero por estado y luego por apellido? Esperaba mejorar la función "ordenar por arriba" y agregar la capacidad de ordenar por al menos 2 campos.

+2

Qué tipo de cosas podría ser "mejor" que eso? (De hecho, usaría '<=' y no '<' para ayudar a mantener estable el género.) – Pointy

+3

Eso no es JSON. –

+0

Puede usar el operador ternario allí: 'return a.lname.toUpperCase()> b.lname.toUpperCase()? 1: -1' –

Respuesta

20

Hay una manera más sencilla. Sólo volver a utilizar su función de clasificación generalizada y concatenar usando ||:

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) 

funciones son baratos. A continuación, puede crear una abstracción para que:

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'] 

Pero entonces perder la capacidad de establecer el orden u otros parámetros en cada uno de ellos.

+0

que son realmente resbaladizos. Intento entender cómo funciona el 'o' para encadenar las funciones. ¿Es porque solo se mueve a la siguiente función sortyBy si el anterior devuelve '0'? ¿O quizás otra forma de decirlo es que seguirá clasificando hasta que se satisfaga la primera clave (es decir, '0') y luego pase a la siguiente? – jiy

+0

Probado el encadenamiento de las funciones sortBy con - funciona muy bien. Lanzar sortByMultiple en la mezcla no fue exitoso, sin embargo, nada se ordenó correctamente. ¡Gracias por una respuesta muy útil! – jiy

+0

@jiy sí, eso es más o menos. Continúe hasta que uno de los criterios arroje un valor distinto de cero. –

15

Alternativamente, es posible que desee considerar el uso de Underscore 's sortBy de modo que usted no tiene que aplicar por sí mismo:

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

¡Gracias! Eso parece extremadamente prometedor. Exactamente lo que estaba buscando – jiy

+0

Los enlaces en su respuesta ya no existen http://underscorejs.org/ y http://underscorejs.org/#sortPor qué son los nuevos enlaces –

3

Esto es algo que pensé que habría implementado por defecto al usar lodash, pero no lo es.

¡Aquí estamos!

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

Sobre la base de un ejemplo más genérico que encontré here

Cuestiones relacionadas