2012-03-20 1 views
19

z tablicy jak poniżej:Jak sortować tablicę z coffeescript?

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

Próbowałem przy użyciu funkcji takich jak to::

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] 

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

i chcesz sortować według nazwiska z coffeescript, można to zrobić

, która została wywołana w ten sposób:

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

ale to nie posortowało poprawnie tablicy.

Czy istnieje sposób sortowania według więcej niż 1 pola, tj. Sortowanie najpierw według stanu, a następnie według nazwiska? Miałem nadzieję ulepszyć powyższą funkcję "sortBy" i dodać możliwość sortowania według co najmniej 2 pól.

+2

Jakie rzeczy może być „lepszy” niż to? (Właściwie użyłbym '<=', a nie '<', aby utrzymać stabilność w sortowaniu.) – Pointy

+3

To nie jest JSON. –

+0

Możesz użyć tamtejszego operatora: 'return a.lname.toUpperCase()> b.lname.toUpperCase()? 1: -1' –

Odpowiedz

20

Jest prostszy sposób. Wystarczy ponownie użyć uogólnioną funkcję sortowania i łączyć je za pomocą ||:

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) 

Funkcje są tanie. Następnie można zbudować abstrakcję:

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

Ale wtedy tracisz możliwość ustawiania kolejności lub innych parametrów na każdym z nich.

+0

to naprawdę śliski. Próbuję zrozumieć, w jaki sposób "lub" działa z łańcuchem funkcji. Czy to dlatego, że przenosi się tylko do następnej funkcji sortyBy, jeśli poprzednia zwraca "0"? A może innym sposobem, aby to ująć, jest to, że będzie on sortować, dopóki pierwszy klucz nie zostanie spełniony (tj. "0"), a następnie przejść do następnego? – jiy

+0

Testowane połączenie funkcji sortBy z lub - działa świetnie! Rzucanie sortByMultiple do miksu nie powiodło się jednak, nic nie zostało posortowane poprawnie. Dziękuję za bardzo pomocną odpowiedź! – jiy

+0

@jiy tak, to prawie tyle. Kontynuuj, aż jedno z kryteriów zwróci wartość niezerową. –

15

Alternatywnie, można rozważyć użycie Underscore „s sortBy tak, że nie trzeba go realizować siebie:

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

Dzięki! To wygląda niezwykle obiecująco. Dokładnie to, czego szukałem – jiy

+0

linki w swojej odpowiedzi nie istnieją już http://underscorejs.org/ i http://underscorejs.org/#sortBy są nowe linki –

3

Jest to coś, co według mnie domyślnie zaimplementowałoby się przy korzystaniu z lodash, ale tak nie jest.

Jesteśmy tutaj!

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

Na podstawie bardziej ogólnych przykład znalazłem here