Как фильтровать данные массива в Javascript в Client [duplicate]

Другое событие NullPointerException возникает, когда объявляется массив объектов, а затем сразу же пытается разыменовать его внутри.

String[] phrases = new String[10];
String keyPhrase = "Bird";
for(String phrase : phrases) {
    System.out.println(phrase.equals(keyPhrase));
}

Этот конкретный NPE можно избежать, если порядок сравнения отменяется ; а именно, использовать .equals для гарантированного непустого объекта.

Все элементы внутри массива инициализируются их общим начальным значением ; для любого типа массива объектов, это означает, что все элементы null.

Вы должны инициализировать элементы в массиве перед доступом или разыменованием их.

String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
    System.out.println(phrase.equals(keyPhrase));
}

1950
задан Bergi 17 June 2015 в 03:09
поделиться

31 ответ

Достаточно просто написать собственную функцию сравнения:

function compare(a,b) {
  if (a.last_nom < b.last_nom)
    return -1;
  if (a.last_nom > b.last_nom)
    return 1;
  return 0;
}

objs.sort(compare);

Или встроенный (c / o Marco Demaio):

objs.sort(function(a,b) {return (a.last_nom > b.last_nom) ? 1 : ((b.last_nom > a.last_nom) ? -1 : 0);} ); 
2735
ответ дан Omar Natour 20 August 2018 в 07:15
поделиться

Я знаю, что этот вопрос слишком стар, но я не видел никакой реализации, подобной моей. Эта версия основана на символе преобразования Шварца .

function sortByAttribute(array, ...attrs) {
  // generate an array of predicate-objects contains
  // property getter, and descending indicator
  let predicates = attrs.map(pred => {
    let descending = pred.charAt(0) === '-' ? -1 : 1;
    pred = pred.replace(/^-/, '');
    return {
      getter: o => o[pred],
      descend: descending
    };
  });
  // schwartzian transform idiom implementation. aka: "decorate-sort-undecorate"
  return array.map(item => {
    return {
      src: item,
      compareValues: predicates.map(predicate => predicate.getter(item))
    };
  })
  .sort((o1, o2) => {
    let i = -1, result = 0;
    while (++i < predicates.length) {
      if (o1.compareValues[i] < o2.compareValues[i]) result = -1;
      if (o1.compareValues[i] > o2.compareValues[i]) result = 1;
      if (result *= predicates[i].descend) break;
    }
    return result;
  })
  .map(item => item.src);
}

Вот пример того, как его использовать:

let games = [
  { name: 'Pako',              rating: 4.21 },
  { name: 'Hill Climb Racing', rating: 3.88 },
  { name: 'Angry Birds Space', rating: 3.88 },
  { name: 'Badland',           rating: 4.33 }
];

// sort by one attribute
console.log(sortByAttribute(games, 'name'));
// sort by mupltiple attributes
console.log(sortByAttribute(games, '-rating', 'name'));
13
ответ дан a8m 20 August 2018 в 07:15
поделиться
  • 1
    У вас есть решение ES5? Тонны старых систем там. Например, я не могу использовать это. – Dylan Hunt 21 July 2018 в 08:49

В соответствии с вашим примером вам нужно отсортировать по двум полям (фамилия, имя), а не по одному. Вы можете использовать библиотеку Alasql , чтобы сделать этот вид в одной строке:

var res = alasql('SELECT * FROM ? ORDER BY last_nom, first_nom',[objs]);

Попробуйте этот пример в jsFiddle .

7
ответ дан agershun 20 August 2018 в 07:15
поделиться

Если у вас есть дубликаты фамилий, вы можете отсортировать их по имени -

obj.sort(function(a,b){
  if(a.last_nom< b.last_nom) return -1;
  if(a.last_nom >b.last_nom) return 1;
  if(a.first_nom< b.first_nom) return -1;
  if(a.first_nom >b.first_nom) return 1;
  return 0;
});
52
ответ дан BadFeelingAboutThis 20 August 2018 в 07:15
поделиться

дополнительные параметры desc для кода Ege Özcan

function dynamicSort(property, desc) {
    if (desc) {
        return function (a, b) {
            return (a[property] > b[property]) ? -1 : (a[property] < b[property]) ? 1 : 0;
        }   
    }
    return function (a, b) {
        return (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
    }
}
6
ответ дан Behnam Yousefi 20 August 2018 в 07:15
поделиться

underscore.js

использовать подчеркивание, его маленькое и удивительное ...

sortBy_.sortBy (list, iterator, [context ]) Возвращает отсортированную копию списка, ранжированную в порядке возрастания по результатам запуска каждого значения через итератор. Итератор также может быть строковым именем свойства для сортировки по (например, длине).

var objs = [ 
  { first_nom: 'Lazslo',last_nom: 'Jamf' },
  { first_nom: 'Pig', last_nom: 'Bodine'  },
  { first_nom: 'Pirate', last_nom: 'Prentice' }
];

var sortedObjs = _.sortBy( objs, 'first_nom' );
157
ответ дан Bill Sambrone 20 August 2018 в 07:15
поделиться
  • 1
    Дэвид, не могли бы вы отредактировать ответ, чтобы сказать: var sortedObjs = _.sortBy( objs, 'first_nom' );. objs будет не сортироваться в результате этого. Функция возвращает отсортированный массив. Это сделает его более явным. – Jess 9 January 2014 в 06:01
  • 2
    Чтобы отсортировать сортировку: var reverseSortedObjs = _.sortBy( objs, 'first_nom' ).reverse(); – Erdal G. 31 January 2016 в 11:43
  • 3
    вам нужно загрузить библиотеку javascript & quot; underscore & quot ;: <script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"> </script> – and-bri 29 May 2017 в 18:28
  • 4
    Также доступен в Lodash для тех, кто предпочитает, чтобы один – WoJ 17 April 2018 в 10:49

С учетом исходного примера:

var objs = [ 
    { first_nom: 'Lazslo', last_nom: 'Jamf'     },
    { first_nom: 'Pig',    last_nom: 'Bodine'   },
    { first_nom: 'Pirate', last_nom: 'Prentice' }
];

Сортировка по нескольким полям:

objs.sort(function(left, right) {
    var last_nom_order = left.last_nom.localeCompare(right.last_nom);
    var first_nom_order = left.first_nom.localeCompare(right.first_nom);
    return last_nom_order || first_nom_order;
});

Примечания

  • a.localeCompare(b) - универсально поддерживается и возвращает -1,0,1, если a<b, a==b, a>b соответственно.
  • || в последней строке дает last_nom приоритет над first_nom.
  • Вычитание работает с числовыми полями: var age_order = left.age - right.age;
  • Отменить в обратном порядке, return -last_nom_order || -first_nom_order || -age_order;
3
ответ дан Bob Stein 20 August 2018 в 07:15
поделиться

Возможно, вам понадобится преобразовать их в нижний регистр, чтобы предотвратить путаницу.

objs.sort(function (a,b) {

var nameA=a.last_nom.toLowerCase(), nameB=b.last_nom.toLowerCase()

if (nameA < nameB)
  return -1;
if (nameA > nameB)
  return 1;
return 0;  //no sorting

})
5
ответ дан Burak Keceli 20 August 2018 в 07:15
поделиться

Простым способом:

objs.sort(function(a,b) {
  return b.last_nom.toLowerCase() < a.last_nom.toLowerCase();
});

См., что '.toLowerCase()' необходимо для предотвращения ошибок при сравнении строк.

9
ответ дан Caio Ladislau 20 August 2018 в 07:15
поделиться
  • 1
    Вы можете использовать функции стрелок , чтобы код стал немного более элегантным: objs.sort( (a,b) => b.last_nom.toLowerCase() < a.last_nom.toLowerCase() ); – Sertage 24 May 2017 в 15:04
  • 2
    Это неверно по той же причине, что объясняется здесь . – Patrick Roberts 18 July 2018 в 09:24
  • 3
    Функции Arrow не достойны ES5. Тонны двигателей по-прежнему ограничены ES5. В моем случае, я нахожу ответ выше значительно лучше, так как я на двигателе ES5 (вынужденном моей компанией) – Dylan Hunt 21 July 2018 в 08:50

Вместо использования специальной функции сравнения вы также можете создать тип объекта с помощью специального метода toString() (который вызывается функцией сравнения по умолчанию):

function Person(firstName, lastName) {
    this.firtName = firstName;
    this.lastName = lastName;
}

Person.prototype.toString = function() {
    return this.lastName + ', ' + this.firstName;
}

var persons = [ new Person('Lazslo', 'Jamf'), ...]
persons.sort();
24
ответ дан Christoph 20 August 2018 в 07:15
поделиться

Я просто улучшил динамическую сортировку Ege Özcan для погружения глубоко внутри объектов. Если Data выглядит так:

obj = [
    {
        a: { a: 1, b: 2, c: 3 },
        b: { a: 4, b: 5, c: 6 }
    },
    { 
        a: { a: 3, b: 2, c: 1 },
        b: { a: 6, b: 5, c: 4 }
}];

, и если вы хотите отсортировать его по свойствам a.a, я думаю, что мое улучшение помогает очень хорошо. Я добавляю новую функциональность к таким объектам:

Object.defineProperty(Object.prototype, 'deepVal', {
    enumerable: false,
    writable: true,
    value: function (propertyChain) {
        var levels = propertyChain.split('.');
        parent = this;
        for (var i = 0; i < levels.length; i++) {
            if (!parent[levels[i]])
                return undefined;
            parent = parent[levels[i]];
        }
        return parent;
    }
});

и изменил функцию return_dynamicSort :

return function (a,b) {
        var result = ((a.deepVal(property) > b.deepVal(property)) - (a.deepVal(property) < b.deepVal(property)));
        return result * sortOrder;
    }

И теперь вы можете сортировать по a.a. следующим образом:

obj.sortBy('a.a');

См. Commplete script in JSFiddle

655
ответ дан Community 20 August 2018 в 07:15
поделиться
  • 1
    Обратите внимание, что имена свойств в JavaScript могут быть любой строкой, и если у вас есть свойства, начинающиеся с & quot; - & quot; (крайне маловероятно и возможно не очень хорошая идея), вам нужно будет изменить функцию dynamicSort, чтобы использовать что-то еще в качестве индикатора обратного сортировки. – Ege Özcan 10 January 2013 в 17:18
  • 2
    Зачем? Это не ответ на оригинальный вопрос и «цель». может быть решена просто с помощью People.sort ((a, b) = & gt; {return a.Name.name.localeCompare (b.Name.name) || a.Name.surname.localeCompare (b.Name.surname)} ) – Tero Tolonen 3 May 2016 в 16:02
  • 3
    Я заметил, что dynamicSort() в приведенном выше примере будет содержать заглавные буквы перед строчными буквами. Например, если у меня есть значения APd, Aklin и Abe - результаты в сортировке ASC должны быть Abe, Aklin, APd. Но с вашим примером, результаты APd, Abe, Aklin. В любом случае, чтобы исправить это поведение? – Lloyd Banks 26 July 2017 в 22:06
  • 4
    @LloydBanks, если вы используете это строго для строк, вы можете использовать var result = a[property].localeCompare(b[property]); вместо var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;. – Ege Özcan 6 August 2017 в 08:55
  • 5
    Точно так же, как верхний ответ, это не удается в случаях, когда существуют неопределенные свойства: [ { a: 5 }, {a:2}, {}, {a:1} ] – dzh 19 January 2018 в 05:09
  • 6
    @ EgeÖzcan Он должен либо поместить предметы в верхнюю, либо нижнюю часть, вот реализация. Я закончил использование pastebin.com/g4dt23jU – dzh 20 January 2018 в 01:37

У меня есть часть кода, которая работает для меня:

arr.sort((a, b) => a.name > b.name)

UPDATE: не работает всегда, поэтому это неверно: (

11
ответ дан Damjan Pavlica 20 August 2018 в 07:15
поделиться

Использование xPrototype: https://github.com/reduardo7/xPrototype/blob/master/README.md#sortbycol1-col2-coln

var o = [ 
  { Name: 'Lazslo', LastName: 'Jamf'     },
  { Name: 'Pig',    LastName: 'Bodine'   },
  { Name: 'Pirate', LastName: 'Prentice' },
  { Name: 'Pag',    LastName: 'Bodine'   }
];


// Original
o.each(function (a, b) { console.log(a, b); });
/*
 0 Object {Name: "Lazslo", LastName: "Jamf"}
 1 Object {Name: "Pig", LastName: "Bodine"}
 2 Object {Name: "Pirate", LastName: "Prentice"}
 3 Object {Name: "Pag", LastName: "Bodine"}
*/


// Sort By LastName ASC, Name ASC
o.sortBy('LastName', 'Name').each(function(a, b) { console.log(a, b); });
/*
 0 Object {Name: "Pag", LastName: "Bodine"}
 1 Object {Name: "Pig", LastName: "Bodine"}
 2 Object {Name: "Lazslo", LastName: "Jamf"}
 3 Object {Name: "Pirate", LastName: "Prentice"}
*/


// Sort by LastName ASC and Name ASC
o.sortBy('LastName'.asc, 'Name'.asc).each(function(a, b) { console.log(a, b); });
/*
 0 Object {Name: "Pag", LastName: "Bodine"}
 1 Object {Name: "Pig", LastName: "Bodine"}
 2 Object {Name: "Lazslo", LastName: "Jamf"}
 3 Object {Name: "Pirate", LastName: "Prentice"}
*/


// Sort by LastName DESC and Name DESC
o.sortBy('LastName'.desc, 'Name'.desc).each(function(a, b) { console.log(a, b); });
/*
 0 Object {Name: "Pirate", LastName: "Prentice"}
 1 Object {Name: "Lazslo", LastName: "Jamf"}
 2 Object {Name: "Pig", LastName: "Bodine"}
 3 Object {Name: "Pag", LastName: "Bodine"}
*/


// Sort by LastName DESC and Name ASC
o.sortBy('LastName'.desc, 'Name'.asc).each(function(a, b) { console.log(a, b); });
/*
 0 Object {Name: "Pirate", LastName: "Prentice"}
 1 Object {Name: "Lazslo", LastName: "Jamf"}
 2 Object {Name: "Pag", LastName: "Bodine"}
 3 Object {Name: "Pig", LastName: "Bodine"}
*/
2
ответ дан Eduardo Cuomo 20 August 2018 в 07:15
поделиться
function compare(propName) {
    return function(a,b) {
        if (a[propName] < b[propName])
            return -1;
        if (a[propName] > b[propName])
            return 1;
        return 0;
    };
}

objs.sort(compare("last_nom"));
5
ответ дан Evgenii 20 August 2018 в 07:15
поделиться
  • 1
    Пожалуйста, рассмотрите возможность редактирования сообщения, чтобы добавить больше объяснений о том, что делает ваш код, и почему он решит проблему. Ответ, который в основном содержит только код (даже если он работает), обычно не помогает OP понять их проблему. – Drenmi 29 October 2015 в 19:16

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

objs.sort(sortBy('last_nom'));

Сценарий:

/**
 * @description 
 * Returns a function which will sort an
 * array of objects by the given key.
 * 
 * @param  {String}  key
 * @param  {Boolean} reverse
 * @return {Function}     
 */
function sortBy(key, reverse) {

  // Move smaller items towards the front
  // or back of the array depending on if
  // we want to sort the array in reverse
  // order or not.
  var moveSmaller = reverse ? 1 : -1;

  // Move larger items towards the front
  // or back of the array depending on if
  // we want to sort the array in reverse
  // order or not.
  var moveLarger = reverse ? -1 : 1;

  /**
   * @param  {*} a
   * @param  {*} b
   * @return {Number}
   */
  return function(a, b) {
    if (a[key] < b[key]) {
      return moveSmaller;
    }
    if (a[key] > b[key]) {
      return moveLarger;
    }
    return 0;
  };

}
13
ответ дан fold_left 20 August 2018 в 07:15
поделиться

Это простая проблема, не знаю, почему у людей такое сложное решение. Простая функция сортировки (на основе алгоритма быстрой сортировки):

function sortObjectsArray(objectsArray, sortKey)
        {
            // Quick Sort:
            var retVal;

            if (1 < objectsArray.length)
            {
                var pivotIndex = Math.floor((objectsArray.length - 1) / 2);  // middle index
                var pivotItem = objectsArray[pivotIndex];                    // value in the middle index
                var less = [], more = [];

                objectsArray.splice(pivotIndex, 1);                          // remove the item in the pivot position
                objectsArray.forEach(function(value, index, array)
                {
                    value[sortKey] <= pivotItem[sortKey] ?                   // compare the 'sortKey' proiperty
                        less.push(value) :
                        more.push(value) ;
                });

                retVal = sortObjectsArray(less, sortKey).concat([pivotItem], sortObjectsArray(more, sortKey));
            }
            else
            {
                retVal = objectsArray;
            }

            return retVal;
        }

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

var myArr = 
        [
            { val: 'x', idx: 3 },
            { val: 'y', idx: 2 },
            { val: 'z', idx: 5 },
        ];
myArr = sortObjectsArray(myArr, 'idx');
4
ответ дан Gil Epshtain 20 August 2018 в 07:15
поделиться
  • 1
    Как выполняется быстрая сортировка в js простое решение? Простой алгоритм, но не простое решение. – Andrew 23 November 2015 в 23:46
  • 2
    Это просто, поскольку он не использует внешние библиотеки и не меняет прототип объекта. На мой взгляд, длина кода не оказывает прямого влияния на сложность кода – Gil Epshtain 24 November 2015 в 13:02
  • 3
    Ну, позвольте мне попробовать разными словами: как изобретать колесо - простое решение? – Roberto14 9 December 2015 в 18:36

Используя lodash или Underscore, его кусок торта

> const sortedList = _.orderBy(objs, [last_nom], [asc]); // asc or desc
2
ответ дан karthik006 20 August 2018 в 07:15
поделиться

Объединив динамическое решение Ege с идеей Vinay, вы получите хорошее надежное решение:

Array.prototype.sortBy = function() {
    function _sortByAttr(attr) {
        var sortOrder = 1;
        if (attr[0] == "-") {
            sortOrder = -1;
            attr = attr.substr(1);
        }
        return function(a, b) {
            var result = (a[attr] < b[attr]) ? -1 : (a[attr] > b[attr]) ? 1 : 0;
            return result * sortOrder;
        }
    }
    function _getSortFunc() {
        if (arguments.length == 0) {
            throw "Zero length arguments not allowed for Array.sortBy()";
        }
        var args = arguments;
        return function(a, b) {
            for (var result = 0, i = 0; result == 0 && i < args.length; i++) {
                result = _sortByAttr(args[i])(a, b);
            }
            return result;
        }
    }
    return this.sort(_getSortFunc.apply(null, arguments));
}

Использование:

// Utility for printing objects
Array.prototype.print = function(title) {
    console.log("************************************************************************");
    console.log("**** "+title);
    console.log("************************************************************************");
    for (var i = 0; i < this.length; i++) {
        console.log("Name: "+this[i].FirstName, this[i].LastName, "Age: "+this[i].Age);
    }
}

// Setup sample data
var arrObj = [
    {FirstName: "Zach", LastName: "Emergency", Age: 35},
    {FirstName: "Nancy", LastName: "Nurse", Age: 27},
    {FirstName: "Ethel", LastName: "Emergency", Age: 42},
    {FirstName: "Nina", LastName: "Nurse", Age: 48},
    {FirstName: "Anthony", LastName: "Emergency", Age: 44},
    {FirstName: "Nina", LastName: "Nurse", Age: 32},
    {FirstName: "Ed", LastName: "Emergency", Age: 28},
    {FirstName: "Peter", LastName: "Physician", Age: 58},
    {FirstName: "Al", LastName: "Emergency", Age: 51},
    {FirstName: "Ruth", LastName: "Registration", Age: 62},
    {FirstName: "Ed", LastName: "Emergency", Age: 38},
    {FirstName: "Tammy", LastName: "Triage", Age: 29},
    {FirstName: "Alan", LastName: "Emergency", Age: 60},
    {FirstName: "Nina", LastName: "Nurse", Age: 54}
];

//Unit Tests
arrObj.sortBy("LastName").print("LastName Ascending");
arrObj.sortBy("-LastName").print("LastName Descending");
arrObj.sortBy("LastName", "FirstName", "-Age").print("LastName Ascending, FirstName Ascending, Age Descending");
arrObj.sortBy("-FirstName", "Age").print("FirstName Descending, Age Ascending");
arrObj.sortBy("-Age").print("Age Descending");
8
ответ дан Mike R 20 August 2018 в 07:15
поделиться
  • 1
    Спасибо за идею! Кстати, пожалуйста, не поощряйте людей менять прототип массива (см. Предупреждение в конце моего примера). – Ege Özcan 10 May 2013 в 15:51

С 2018 года существует гораздо более короткое и элегантное решение. Просто используйте. Array.prototype.sort () .

Пример:

var items = [
  { name: 'Edward', value: 21 },
  { name: 'Sharpe', value: 37 },
  { name: 'And', value: 45 },
  { name: 'The', value: -12 },
  { name: 'Magnetic', value: 13 },
  { name: 'Zeros', value: 37 }
];

// sort by value
items.sort(function (a, b) {
  return a.value - b.value;
});
5
ответ дан Oleg 20 August 2018 в 07:15
поделиться
  • 1
    В вопросе строки использовались для сравнения, а не числа. Ваш ответ отлично подходит для сортировки по номерам, но не так хорош для сравнения по строкам. – smcstewart 18 June 2018 в 10:02
  • 2
    As of 2018 Я думаю, вы имеете в виду «По состоянию на 1997 год», когда была выпущена спецификация для 1-го издания ECMAScript и определена Array.prototype.sort() ... См. §15.4.4.5 на стр. 79 – Patrick Roberts 18 July 2018 в 09:27

Не поймите, почему люди делают это настолько сложным:

objs.sort(function(a, b){
  return a.last_nom > b.last_nom;
});

Для более строгих движков:

objs.sort(function(a, b){
  return a.last_nom == b.last_nom ? 0 : +(a.last_nom > b.last_nom) || -1;
});

Смените оператор, чтобы он отсортировался по обратному алфавитному порядку.

144
ответ дан p3lim 20 August 2018 в 07:15
поделиться
  • 1
    Это фактически неверно, так как функция, используемая в сортировке, должна возвращать -1, 0 или 1, но вышеприведенная функция возвращает логическое значение. Сорт отлично работает в хроме, но не работает, например, в PhantomJS. См. code.google.com/p/phantomjs/issues/detail?id=1090 – schup 22 April 2014 в 16:05
  • 2
    Некоторые двигатели объясняют глупость, таким образом, это было связано с этим. Я обновил свой ответ с помощью правильной версии. – p3lim 22 April 2014 в 20:23
  • 3
    Я предлагаю редактировать, чтобы вынуть первую версию. Его более сжатый, поэтому выглядит более привлекательным, но он не работает, по крайней мере, не надежно. Если кто-то пробует это в одном браузере, и он работает, они могут даже не осознавать, что у них есть проблема (особенно если они не читают комментарии). Вторая версия работает правильно, поэтому в первую очередь не нужно. – Kate 11 March 2016 в 16:01
  • 4
    @Simon Я действительно оценил наличие «немного неправильного». сначала, поскольку более строгая реализация занимает несколько секунд, чтобы разобрать и понять и будет намного сложнее без нее. – Aaron Sherman 24 June 2016 в 16:50
  • 5
    @ Lion789 просто сделайте это: if(a.count == b.count) return a.name > b.name; else return a.count > b.count; – p3lim 7 May 2017 в 17:16

Я не видел такого конкретного подхода, поэтому я хотел бы использовать метод сравнения, который мне нравится использовать как для string, так и для number:

const objs = [ 
  { first_nom: 'Lazslo', last_nom: 'Jamf'     },
  { first_nom: 'Pig',    last_nom: 'Bodine'   },
  { first_nom: 'Pirate', last_nom: 'Prentice' }
];

const sortBy = fn => (a, b) => -(fn(a) < fn(b)) || +(fn(a) > fn(b))
const getLastName = o => o.last_nom
const sortByLastName = sortBy(getLastName)

objs.sort(sortByLastName)
console.log(objs.map(getLastName))

Вот объяснение sortBy():

sortBy() принимает параметр fn, который выбирает какое значение для объекта для использования в качестве сравнения и возвращает функцию, которая может передаются непосредственно на Array.prototype.sort(). В этом примере мы используем o.last_nom как значение для сравнения, поэтому всякий раз, когда мы получаем два объекта через Array.prototype.sort(), такие как

{ first_nom: 'Lazslo', last_nom: 'Jamf' }

и

{ first_nom: 'Pig', last_nom: 'Bodine' }

мы используем

(a, b) => -(fn(a) < fn(b)) || +(fn(a) > fn(b))

для их сравнения.

Вспоминая, что fn = o => o.last_nom, мы можем развернуть функцию сравнения с эквивалентом

(a, b) => -(a.last_nom < b.last_nom) || +(a.last_nom > b.last_nom)

. Логическое Оператор OR || имеет функцию короткого замыкания, которая здесь очень полезна. Из-за того, как это работает, тело функции выше означает

if (a.last_nom < b.last_nom) return -1
return +(a.last_nom > b.last_nom)

Итак, если a < b мы возвращаем -1, в противном случае, если a > b, то мы возвращаем +1, но если a == b, тогда a < b и a > b являются ложными, поэтому он возвращает +0.

В качестве дополнительного бонуса здесь эквивалент в ECMAScript 5.1 без функций стрелок, что, к сожалению, не совсем так:

var objs = [ 
  { first_nom: 'Lazslo', last_nom: 'Jamf'     },
  { first_nom: 'Pig',    last_nom: 'Bodine'   },
  { first_nom: 'Pirate', last_nom: 'Prentice' }
];

var sortBy = function (fn) {
  return function (a, b) {
    return -(fn(a) < fn(b)) || +(fn(a) > fn(b))
  }
}

var getLastName = function (o) { return o.last_nom }
var sortByLastName = sortBy(getLastName)

objs.sort(sortByLastName)
console.log(objs.map(getLastName))

3
ответ дан Patrick Roberts 20 August 2018 в 07:15
поделиться

Еще одна опция:

var someArray = [...];

function generateSortFn(prop, reverse) {
    return function (a, b) {
        if (a[prop] < b[prop]) return reverse ? 1 : -1;
        if (a[prop] > b[prop]) return reverse ? -1 : 1;
        return 0;
    };
}

someArray.sort(generateSortFn('name', true));

сортирует по возрастанию по умолчанию.

6
ответ дан Ravshan Samandarov 20 August 2018 в 07:15
поделиться
objs.sort(function(a,b){return b.last_nom>a.last_nom})
5
ответ дан Roshni Bokade 20 August 2018 в 07:15
поделиться
  • 1
    На самом деле, похоже, это не работало, пришлось использовать принятый ответ. Это неправильно сортировалось. – madprops 21 February 2017 в 12:15

Lodash.js (надмножество Underscore.js )

Хорошо не добавлять рамки для каждой простой части логики, но полагаться

Lodash выпускает очень чистый код и способствует более функциональному программированию , который приводит к тому, что он работает на хорошо проверенных средах утилиты, ускоряет разработку и уменьшает количество написанных ошибок. в меньшем количестве ошибок. В одном взгляде становится ясно, что за цель, если код.

Проблема OP может быть просто решена как:

const sortedObjs = _.sortBy(objs, 'last_nom');

Подробнее? Например. у нас есть следующий вложенный объект:

const users = [
  { 'user': {'name':'fred', 'age': 48}},
  { 'user': {'name':'barney', 'age': 36 }},
  { 'user': {'name':'wilma'}},
  { 'user': {'name':'betty', 'age': 32}}
];

Теперь мы можем использовать стенографию _. свойство user.age, чтобы указать путь к свойству, которое должно быть сопоставлено. Мы будем сортировать объекты пользователя по вложенному возрасту. Да, это позволяет сопоставлять вложенные свойства!

const sortedObjs = _.sortBy(users, ['user.age']);

Хотите, чтобы это было отменено? Нет проблем. Используйте _. Reverse .

const sortedObjs = _.reverse(_.sortBy(users, ['user.age']));

Хотите комбинировать оба с помощью Chaining ?

const sortedObjs = _.chain(users).sortBy('user.age').reverse().value();
14
ответ дан Seraf 20 August 2018 в 07:15
поделиться

Использование Ramda,

npm установка ramda

import R from 'ramda'
var objs = [ 
    { first_nom: 'Lazslo', last_nom: 'Jamf'     },
    { first_nom: 'Pig',    last_nom: 'Bodine'   },
    { first_nom: 'Pirate', last_nom: 'Prentice' }
];
var ascendingSortedObjs = R.sortBy(R.prop('last_nom'), objs)
var descendingSortedObjs = R.reverse(ascendingSortedObjs)
4
ответ дан Sridhar Sg 20 August 2018 в 07:15
поделиться

Здесь много хороших ответов, но я хотел бы отметить, что их можно очень просто расширить, чтобы добиться более сложной сортировки. Единственное, что вам нужно сделать, это использовать оператор OR для цепочки сравнения, например:

objs.sort((a,b)=> fn1(a,b) || fn2(a,b) || fn3(a,b) )

Где fn1, fn2, ... являются функциями сортировки, которые возвращают [- 1,0,1]. Это приводит к «сортировке по fn1», «сортировке по fn2», которая в значительной степени равна ORDER BY в SQL.

Это решение основано на поведении оператора ||, который оценивает значение первое оцениваемое выражение, которое может быть преобразовано в true .

Простейшая форма имеет только одну встроенную функцию:

// ORDER BY last_nom
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) )

Имея два шага с last_nom , порядок сортировки first_nom будет выглядеть так:

// ORDER_BY last_nom, first_nom
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) || 
                  a.first_nom.localeCompare(b.first_nom)  )

Общая функция сравнения может быть примерно такой:

// ORDER BY <n>
let cmp = (a,b,n)=>a[n].localeCompare(b[n])

Эта функция может быть расширена для поддержки числовых полей , чувствительность к регистру, произвольные типы данных и т. д.

Вы можете использовать его с привязкой к ним по приоритету сортировки:

// ORDER_BY last_nom, first_nom
objs.sort((a,b)=> cmp(a,b, "last_nom") || cmp(a,b, "first_nom") )
// ORDER_BY last_nom, first_nom DESC
objs.sort((a,b)=> cmp(a,b, "last_nom") || -cmp(a,b, "first_nom") )
// ORDER_BY last_nom DESC, first_nom DESC
objs.sort((a,b)=> -cmp(a,b, "last_nom") || -cmp(a,b, "first_nom") )

. Дело в том, что чистый JavaScript с функциональным подходом может принять вас долгий путь без внешних библиотек или сложного кода. Это также очень эффективно, так как не нужно выполнять синтаксический анализ строк

15
ответ дан Tero Tolonen 20 August 2018 в 07:15
поделиться

В ES6 / ES2015 или более поздней версии вы можете сделать так:

objs.sort((a, b) => a.last_nom.localeCompare(b.last_nom));
143
ответ дан Vlad Bezden 20 August 2018 в 07:15
поделиться
  • 1
    это было доступно с JS 1.1, кусок стрелки жира - это часть ES6 / 2015. Но все же очень полезный и лучший ответ на мой взгляд – Jon Harding 22 February 2016 в 21:30
  • 2
    @PratikKelwalkar: если вам нужно изменить его, просто переключите a и b сравнение: objs.sort ((a, b) = & gt; b.last_nom.localeCompare (a.last_nom)); – Vlad Bezden 26 May 2016 в 18:24
  • 3
    можно также использовать индекс, чтобы адресовать поле для сортировки: вместо last_nom используйте только число в массиве: 1? – and-bri 29 May 2017 в 18:15
  • 4
    @VladBezden благодарит за ваш ответ! Это решение является первым с очень небольшим программным усилием и правильными результатами сортировки и строковым массивом, например: [«Name1», «Name10», «Name2», «something else»), «Name11». У меня была правильная работа с objs.sort((a, b) => a.last_nom.localeCompare(b.last_nom, undefined, {numberic: true})); – scipper 9 January 2018 в 09:49

Простое и быстрое решение этой проблемы с использованием наследования прототипа:

Array.prototype.sortBy = function(p) {
  return this.slice(0).sort(function(a,b) {
    return (a[p] > b[p]) ? 1 : (a[p] < b[p]) ? -1 : 0;
  });
}

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

objs = [{age:44,name:'vinay'},{age:24,name:'deepak'},{age:74,name:'suresh'}];

objs.sortBy('age');
// Returns
// [{"age":24,"name":"deepak"},{"age":44,"name":"vinay"},{"age":74,"name":"suresh"}]

objs.sortBy('name');
// Returns
// [{"age":24,"name":"deepak"},{"age":74,"name":"suresh"},{"age":44,"name":"vinay"}]

Обновление: больше не изменяет исходный массив.

38
ответ дан Web_Designer 20 August 2018 в 07:15
поделиться
  • 1
    Он просто не возвращает другой массив. но на самом деле сортирует оригинал !. – Vinay Aggarwal 21 July 2012 в 06:43
  • 2
    Если вы хотите убедиться, что используете натуральный сорт с цифрами (например, 0,1,2,10,11 и т. Д.), Используйте parseInt с набором Radix. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… so: return (parseInt (a [p], 10) & gt; parseInt (b [p], 10 ))? 1: (parseInt (a [p], 10) & lt; parseInt (b [p], 10))? -1: 0; – Paul 11 May 2015 в 19:14
  • 3
    @codehuntr Спасибо за исправление. но я думаю, вместо того, чтобы делать функцию сортировки для этой сенсибилизации, лучше, если мы создадим отдельную функцию для фиксации типов данных. Поскольку функция сортировки не может определить, какое свойство будет содержать какие данные. :) – Vinay Aggarwal 21 May 2015 в 16:55
  • 4
    Очень хорошо. Переверните стрелки, чтобы получить эффект asc / desc. – Abdul Sadik Yalcin 15 November 2017 в 16:08
  • 5

Сортировка (подробнее) Сложные массивы объектов

Поскольку вы, вероятно, сталкиваетесь с более сложными структурами данных, такими как этот массив, я бы расширил решение.

TL; DR

Более вместительная версия на основе @ ege-Özcan очень симпатичного ответа .

Проблема

Я столкнулся с ниже и не мог ее изменить. Я также не хотел временно сгладить объект. Я также не хотел использовать underscore / lodash, главным образом по соображениям производительности и забавой для его реализации.

var People = [
   {Name: {name: "Name", surname: "Surname"}, Middlename: "JJ"},
   {Name: {name: "AAA", surname: "ZZZ"}, Middlename:"Abrams"},
   {Name: {name: "Name", surname: "AAA"}, Middlename: "Wars"}
];

Цель

Цель состоит в том, чтобы отсортировать ее в основном с помощью People.Name.name и, во-вторых, People.Name.surname

Препятствия

Теперь в базовом решении используется скобка для вычисления свойств для динамического сортировки. Здесь, однако, нам также придется динамически создавать условные обозначения скобок, так как вы ожидаете, что некоторые из них People['Name.name'] будут работать, а это не так.

С другой стороны, выполнение People['Name']['name'] является статическим и позволяет вам спуститься на n -й уровень.

Решение

Основным дополнением здесь будет спуск по дереву объектов и определение значения последнего листа, вы должны указать, а также любой промежуточный лист.

var People = [
   {Name: {name: "Name", surname: "Surname"}, Middlename: "JJ"},
   {Name: {name: "AAA", surname: "ZZZ"}, Middlename:"Abrams"},
   {Name: {name: "Name", surname: "AAA"}, Middlename: "Wars"}
];

People.sort(dynamicMultiSort(['Name','name'], ['Name', '-surname']));
// Results in...
// [ { Name: { name: 'AAA', surname: 'ZZZ' }, Middlename: 'Abrams' },
//   { Name: { name: 'Name', surname: 'Surname' }, Middlename: 'JJ' },
//   { Name: { name: 'Name', surname: 'AAA' }, Middlename: 'Wars' } ]

// same logic as above, but strong deviation for dynamic properties 
function dynamicSort(properties) {
  var sortOrder = 1;
  // determine sort order by checking sign of last element of array
  if(properties[properties.length - 1][0] === "-") {
    sortOrder = -1;
    // Chop off sign
    properties[properties.length - 1] = properties[properties.length - 1].substr(1);
  }
  return function (a,b) {
    propertyOfA = recurseObjProp(a, properties)
    propertyOfB = recurseObjProp(b, properties)
    var result = (propertyOfA < propertyOfB) ? -1 : (propertyOfA > propertyOfB) ? 1 : 0;
    return result * sortOrder;
  };
}

/**
 * Takes an object and recurses down the tree to a target leaf and returns it value
 * @param  {Object} root - Object to be traversed.
 * @param  {Array} leafs - Array of downwards traversal. To access the value: {parent:{ child: 'value'}} -> ['parent','child']
 * @param  {Number} index - Must not be set, since it is implicit.
 * @return {String|Number}       The property, which is to be compared by sort.
 */
function recurseObjProp(root, leafs, index) {
  index ? index : index = 0
  var upper = root
  // walk down one level
  lower = upper[leafs[index]]
  // Check if last leaf has been hit by having gone one step too far.
  // If so, return result from last step.
  if (!lower) {
    return upper
  }
  // Else: recurse!
  index++
  // HINT: Bug was here, for not explicitly returning function
  // https://stackoverflow.com/a/17528613/3580261
  return recurseObjProp(lower, leafs, index)
}

/**
 * Multi-sort your array by a set of properties
 * @param {...Array} Arrays to access values in the form of: {parent:{ child: 'value'}} -> ['parent','child']
 * @return {Number} Number - number for sort algorithm
 */
function dynamicMultiSort() {
  var args = Array.prototype.slice.call(arguments); // slight deviation to base

  return function (a, b) {
    var i = 0, result = 0, numberOfProperties = args.length;
    // REVIEW: slightly verbose; maybe no way around because of `.sort`-'s nature
    // Consider: `.forEach()`
    while(result === 0 && i < numberOfProperties) {
      result = dynamicSort(args[i])(a, b);
      i++;
    }
    return result;
  }
}

Пример

Рабочий пример в JSBin

655
ответ дан Community 20 August 2018 в 07:15
поделиться
  • 1
    Обратите внимание, что имена свойств в JavaScript могут быть любой строкой, и если у вас есть свойства, начинающиеся с & quot; - & quot; (крайне маловероятно и возможно не очень хорошая идея), вам нужно будет изменить функцию dynamicSort, чтобы использовать что-то еще в качестве индикатора обратного сортировки. – Ege Özcan 10 January 2013 в 17:18
  • 2
    Зачем? Это не ответ на оригинальный вопрос и «цель». может быть решена просто с помощью People.sort ((a, b) = & gt; {return a.Name.name.localeCompare (b.Name.name) || a.Name.surname.localeCompare (b.Name.surname)} ) – Tero Tolonen 3 May 2016 в 16:02
  • 3
    Я заметил, что dynamicSort() в приведенном выше примере будет содержать заглавные буквы перед строчными буквами. Например, если у меня есть значения APd, Aklin и Abe - результаты в сортировке ASC должны быть Abe, Aklin, APd. Но с вашим примером, результаты APd, Abe, Aklin. В любом случае, чтобы исправить это поведение? – Lloyd Banks 26 July 2017 в 22:06
  • 4
    @LloydBanks, если вы используете это строго для строк, вы можете использовать var result = a[property].localeCompare(b[property]); вместо var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;. – Ege Özcan 6 August 2017 в 08:55
  • 5
    Точно так же, как верхний ответ, это не удается в случаях, когда существуют неопределенные свойства: [ { a: 5 }, {a:2}, {}, {a:1} ] – dzh 19 January 2018 в 05:09
  • 6
    @ EgeÖzcan Он должен либо поместить предметы в верхнюю, либо нижнюю часть, вот реализация. Я закончил использование pastebin.com/g4dt23jU – dzh 20 January 2018 в 01:37
675
ответ дан Community 31 October 2018 в 06:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: