Как я могу сделать asc и desc сортировку, используя underscore.js?

166

В настоящее время я использую underscorejs для сортировки JSON сортировки. Теперь я попросил сделать ascendingи descendingсортировку с использованием underscore.js. Я не вижу ничего похожего в документации. Как мне этого добиться?

Рахул
источник
1
Пожалуйста, добавьте пример того, что вы сортируете и как.
Джон
Что вы сортируете? Числа? Строки? Сроки? Что-то другое?
Му слишком коротко
@muistooshort Я сортирую массив объектов. Таким образом, метод sortBy идеально подходит моим критериям для сортировки по возрастанию, но не наоборот.
Рахул
Если вы сортируете по числу, то ваша sortByфункция может быть, return -nно это не сработает для строк; отсюда вопрос о том, какие вещи вы сортируете.
мю слишком коротка
2
С Lodash вы можете использовать сокращение _.sortBy([1,4,3,2]).reverse()или как, _.chain([1,4,3,2]).sortBy().reverse().value()если вы не хотите использовать reverse()прототип Array.
GFoley83

Ответы:

363

Вы можете использовать .sortBy, он всегда вернет список по возрастанию :

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

Но вы можете использовать метод .reverse, чтобы получить его по убыванию :

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

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

Или при работе с числами добавьте отрицательный знак к возврату, чтобы убрать список:

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

Под капотом .sortByиспользуются встроенные .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
источник
9
Последнее решение, т.е. добавление отрицательного знака к возвращаемому num, идеально.
Винеш
Почему вы думаете, что это пузырьковая сортировка? Под капотом .sortBy()называются встроенные функции Array.sort(), алгоритм которых зависит от производителей браузеров, но пузырьковая сортировка вряд ли будет их выбором.
Рене Саарсоо
Разве это не увеличивает сложность времени? Это приводит к тому, что список сортируется дважды.
user1477388
@ user1477388 Я не уверен, что ты имеешь в виду, отсортированный дважды?
andlrc
@andlrc Итак, когда вы вызываете _.sortBy(arr, function), я предполагаю, что он зацикливается на каждом элементе и выполняет некоторую логику, чтобы вернуть отсортированный массив. Затем, когда вы вызываете Array.prototype.reverse()его, вероятно, снова зацикливается на каждом элементе и выполняет некоторую логику для возврата обращенного массива. Таким образом, вы зацикливаете массив дважды.
user1477388
57

По убыванию, используя подчеркивание, можно сделать, умножив возвращаемое значение на -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]

Если вы сортируете по строкам, а не по номерам, вы можете использовать метод charCodeAt (), чтобы получить значение Юникода.

//Descending Order Strings:
_.sortBy(['a', 'b', 'c'], function(s){ 
    return s.charCodeAt() * -1;
});
jEremyB
источник
3
Я пытаюсь отсортировать по алфавиту - умножение на -1 не является допустимой операцией. :)
rythos42
Это стоит использовать, но не указано в вопросе. Однако умножение строки на -1 является допустимой операцией. Он возвращает NaN, который является действительным результатом.
JeremyB
1
не забудьте назначить массив обратно тоже! SOME_ARR = _.sortBy (SOME_ARR, function (num) {SOME_FUNC ...});
АКМ
4
charCodeAt будет «возвращать Unicode символа по указанному индексу в строке», поэтому его можно использовать для сортировки по символам в строке, но, как показано, он не «сортирует по строке», а сортирует по символу в строке
Энтони
2
Сортирует только по первому символу и учитывает регистр.
Эйдан
50

В обратном методе массива прототип изменяет массив и возвращает ссылку на него, что означает , что вы можете сделать это:

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

Также подчеркивающая документация гласит:

Кроме того, методы прототипа Array проксируются через связанный объект Underscore, так что вы можете вставить reverseили pushв свою цепочку и продолжить модифицировать массив.

это означает, что вы также можете использовать .reverse()во время цепочки:

var sortedDescAndFiltered = _.chain(collection)
    .sortBy('propertyName')
    .reverse()
    .filter(_.property('isGood'))
    .value();
Эмиль Лундберг
источник
Это самый простой способ для обратной / нисходящей сортировки, когда речь идет о самых простых случаях использования.
Дэн Аткинсон
2
Для алфавитной сортировки _.sortBy(collection, item => item. propertyName.toLowerCase());
без учета
это не работает, если в массиве есть отрицательные числа.
Шрути Капур
@ShrutiKapoor Да, это так. Почему бы и нет?
Эмиль Лундберг
5
Что касается производительности, было бы предпочтительно сначала применить фильтр, а затем отсортировать (оставшиеся) значения.
Саран
12

По аналогии с библиотекой Underscore есть еще одна библиотека с именем lodash, в которой есть один метод orderBy, который принимает параметр для определения порядка сортировки. Вы можете использовать его как

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

По какой-то причине, это не задокументировано на сайте документации.

Минкеш Джайн
источник
Я думаю, что вы перепутали подчеркивание с lodash . Только последний имеет упомянутую функцию orderBy .
Томас Марти
Да, мой плохой. Обновлю ответ. Спасибо за исправление :)
Минкеш Джайн
orderByсупер полезно! Гораздо лучше, чем использование reverse, поскольку он сохраняет свойство стабильной сортировки, которое я ищу.
Flimm
Не работает для меня почему-то upadte: его lodash (
aleXela
0

Подчеркни Миксин

Расширяя ответ @ emil_lundberg, вы также можете написать «mixin», если вы используете Underscore для создания пользовательской функции для сортировки, если это своего рода сортировка, которую вы могли бы повторить в приложении где-нибудь.

Например, может быть, у вас есть контроллер или просмотр результатов сортировки с порядком сортировки «ASC» или «DESC», и вы хотите переключаться между ними, вы можете сделать что-то вроде этого:

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

Пример использования

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

Вот JSFiddle, демонстрирующий это: JSFiddle для SortBy Mixin

RoboBear
источник