Jak mogę posortować rosnąco i malejąco za pomocą underscore.js?

166

Obecnie używam znaków podkreślenia do sortowania plików JSON. Teraz poprosiłem o wykonanie ascendingi descendingsortowanie przy użyciu podkreślenia.js. Nie widzę w dokumentacji nic o tym samym. Jak mogę to osiągnąć?

Rahul
źródło
1
Dodaj przykład tego, co sortujesz i jak.
Jon
Co sortujesz? Liczby? Smyczki? Daktyle? Coś innego?
mu jest za krótkie
@muistooshort Sortuję tablicę obiektów. Zatem metoda sortBy doskonale pasuje do moich kryteriów sortowania rosnącego, ale nie na odwrót.
Rahul
Jeśli sortujesz według liczby, twoja sortByfunkcja może być, return -nale to nie zadziała w przypadku łańcuchów; stąd pytanie, jakie rzeczy sortujesz.
mu jest za krótkie
2
W Lodash możesz używać shorthand like _.sortBy([1,4,3,2]).reverse()lub _.chain([1,4,3,2]).sortBy().reverse().value()jeśli nie chcesz używać reverse()prototypu Array.
GFoley83,

Odpowiedzi:

363

Możesz użyć .sortBy, zawsze zwróci listę rosnącą :

_.sortBy([2, 3, 1], function(num) {
    return num;
}); // [1, 2, 3]

Ale możesz użyć metody .reverse , aby uzyskać malejąco :

var array = _.sortBy([2, 3, 1], function(num) {
    return num;
});

console.log(array); // [1, 2, 3]
console.log(array.reverse()); // [3, 2, 1]

Lub w przypadku liczb dodaj znak minus do powrotu, aby zejść z listy:

_.sortBy([-3, -2, 2, 3, 1, 0, -1], function(num) {
    return -num;
}); // [3, 2, 1, 0, -1, -2, -3]

Pod maską .sortByzastosowano wbudowane .sort([handler]):

// Default is ascending:
[2, 3, 1].sort(); // [1, 2, 3]

// But can be descending if you provide a sort handler:
[2, 3, 1].sort(function(a, b) {
    // a = current item in array
    // b = next item in array
    return b - a;
});
andlrc
źródło
9
Ostatnie rozwiązanie tj. Dodanie znaku ujemnego do zwracanej liczby jest idealne.
Vinesh
Dlaczego myślisz, że to sortowanie bąbelkowe? .sortBy()Wbudowane wywołania pod maską Array.sort(), których algorytm zależy od dostawców przeglądarek, ale sortowanie bąbelkowe raczej nie będzie ich wyborem.
Rene Saarsoo,
Czy to nie zwiększa złożoności czasowej? Powoduje to dwukrotne posortowanie listy.
user1477388
@ user1477388 Nie jestem pewien, co masz na myśli, mówiąc o sortowaniu dwukrotnie?
andlrc
@andlrc Tak więc, kiedy dzwonisz _.sortBy(arr, function), zakładam, że zapętla się nad każdym elementem i wykonuje jakąś logikę, aby zwrócić posortowaną tablicę. Następnie, gdy wywołasz Array.prototype.reverse()to, prawdopodobnie ponownie zapętli się nad każdym elementem i wykonuje jakąś logikę, aby zwrócić odwróconą tablicę. Dlatego dwukrotnie zapętlasz tablicę.
user1477388
57

Porządek malejący za pomocą podkreślenia można wykonać, mnożąc zwracaną wartość przez -1.

//Ascending Order:
_.sortBy([2, 3, 1], function(num){
    return num;
}); // [1, 2, 3]


//Descending Order:
_.sortBy([2, 3, 1], function(num){
    return num * -1;
}); // [3, 2, 1]

Jeśli sortujesz według ciągów, a nie liczb, możesz użyć metody charCodeAt (), aby uzyskać wartość Unicode.

//Descending Order Strings:
_.sortBy(['a', 'b', 'c'], function(s){ 
    return s.charCodeAt() * -1;
});
jEremyB
źródło
3
Próbuję posortować alfabetycznie - mnożenie przez -1 nie jest prawidłową operacją. :)
rythos42
Warto go użyć, ale nie został określony w pytaniu. Jednak pomnożenie ciągu przez -1 jest prawidłową operacją. Zwraca NaN, który jest prawidłowym wynikiem.
jEremyB
1
pamiętaj o ponownym przypisaniu tablicy! SOME_ARR = _.sortBy (SOME_ARR, function (num) {SOME_FUNC ...});
aqm
4
charCodeAt „zwróci kod Unicode znaku o określonym indeksie w ciągu”, dzięki czemu można go użyć do sortowania według znaków w ciągu, ale jak pokazano, nie sortuje według ciągu, sortuje według znaku w ciągu
Anthony
2
Sortuje tylko według pierwszego znaku i rozróżnia wielkość liter.
Aidan
50

Tego prototypu Array metoda odwróconej modyfikuje tablicy i zwraca referencję do niego, co oznacza, że można to zrobić:

var sortedAsc = _.sortBy(collection, 'propertyName');
var sortedDesc = _.sortBy(collection, 'propertyName').reverse();

Ponadto dokumentacja z podkreśleniem czyta:

Ponadto metody prototypu Array są przesyłane przez serwer proxy za pośrednictwem połączonego obiektu Underscore, dzięki czemu można wsunąć a reverselub a pushdo łańcucha i kontynuować modyfikowanie tablicy.

co oznacza, że ​​możesz również użyć .reverse()podczas łączenia:

var sortedDescAndFiltered = _.chain(collection)
    .sortBy('propertyName')
    .reverse()
    .filter(_.property('isGood'))
    .value();
Emil Lundberg
źródło
Jest to najprostsza metoda sortowania odwrotnego / malejącego, jeśli chodzi o najprostsze przypadki użycia.
Dan Atkinson
2
Aby wykonać sortowanie alfabetyczne bez rozróżniania wielkości liter:_.sortBy(collection, item => item. propertyName.toLowerCase());
XåpplI'-I0llwlg'I -
to nie działa, jeśli w tablicy są liczby ujemne.
Shruti Kapoor,
@ShrutiKapoor Tak, to prawda. Dlaczego by tego nie zrobił?
Emil Lundberg
5
Ze względu na wydajność najlepiej byłoby najpierw zastosować filtr, a następnie posortować (pozostałe) wartości.
Saran,
12

Podobnie jak w przypadku biblioteki Underscore, istnieje inna biblioteka o nazwie „lodash”, która ma jedną metodę „orderBy”, która pobiera parametr w celu określenia kolejności sortowania. Możesz go używać jak

_.orderBy('collection', 'propertyName', 'desc')

Z jakiegoś powodu nie jest to udokumentowane w dokumentacji witryny.

Minkesh Jain
źródło
Myślę, że pomyliłeś podkreślenie z lodash . Tylko ta ostatnia ma wspomnianą funkcję orderBy .
Thomas Marti
Tak, moja wina. Zaktualizuje odpowiedź. Dzięki za poprawienie :)
Minkesh Jain
orderBy, super przydatne! Znacznie lepsze niż używanie odwrócenia, ponieważ zachowuje stabilną właściwość sortowania, której szukam.
Flimm
Z jakiegoś powodu nie działa dla mnie upadte: jego lodash (
aleXela
0

Mixins podkreślenia

Rozszerzając odpowiedź @ emil_lundberg, możesz również napisać „mixin”, jeśli używasz podkreślenia, aby utworzyć niestandardową funkcję do sortowania, jeśli jest to rodzaj sortowania, który możesz powtórzyć w jakiejś aplikacji.

Na przykład, być może masz kontroler lub widok sortowania wyników z porządkiem sortowania „ASC” lub „DESC” i chcesz przełączać się między tym sortowaniem, możesz zrobić coś takiego:

Mixin.js

_.mixin({
    sortByOrder: function(stooges, prop, order) {
      if (String(order) === "desc") {
          return _.sortBy(stooges, prop).reverse();
      } else if (String(order) === "asc") {
          return _.sortBy(stooges, prop);
      } else {
          return stooges;
      }
    }
})

Przykład użycia

var sort_order = "asc";
var stooges = [
  {name: 'moe', age: 40}, 
  {name: 'larry', age: 50}, 
  {name: 'curly', age: 60},
  {name: 'July', age: 35},
  {name: 'mel', age: 38}
 ];

_.mixin({
    sortByOrder: function(stooges, prop, order) {
    if (String(order) === "desc") {
        return _.sortBy(stooges, prop).reverse();
    } else if (String(order) === "asc") {
        return _.sortBy(stooges, prop);
    } else {
        return stooges;
    }
  }
})


// find elements
var banner = $("#banner-message");
var sort_name_btn = $("button.sort-name");
var sort_age_btn = $("button.sort-age");

function showSortedResults(results, sort_order, prop) {
    banner.empty();
    banner.append("<p>Sorting: " + prop + ', ' + sort_order + "</p><hr>")
  _.each(results, function(r) {
    banner.append('<li>' + r.name + ' is '+ r.age + ' years old.</li>');
  }) 
}

// handle click and add class
sort_name_btn.on("click", function() {
  sort_order = (sort_order === "asc") ? "desc" : "asc"; 
    var sortedResults = _.sortByOrder(stooges, 'name', sort_order);
  showSortedResults(sortedResults, sort_order, 'name');
})

sort_age_btn.on('click', function() {
    sort_order = (sort_order === "asc") ? "desc" : "asc"; 
    var sortedResults = _.sortByOrder(stooges, 'age', sort_order);
  showSortedResults(sortedResults, sort_order, 'age');
})

Oto JSFiddle demonstrujący to: JSFiddle dla SortBy Mixin

RoboBear
źródło