문자열 속성 값으로 객체 배열 정렬


2763

JavaScript 객체 배열이 있습니다.

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

last_nomJavaScript 에서 값을 기준 으로 정렬하려면 어떻게 합니까?

나는 알고 sort(a,b)있지만 문자열과 숫자에서만 작동하는 것 같습니다. toString()객체에 메소드 를 추가해야 합니까?


7
이 스크립트를 사용하면 자신 만의 비교 함수 나 분류기를 작성하지 않는 한 그렇게 할 수 있습니다. thomasfrank.se/sorting_things.html
Baversjo

가장 빠른 방법은 브라우저와 노드 모두에서 기본적으로 작동하는 모든 유형의 입력, 계산 필드 및 사용자 정의 정렬 순서를 지원 하는 동형 정렬 배열 모듈 을 사용하는 것 입니다.
Lloyd

답변:


3920

자체 비교 함수를 작성하는 것은 쉽습니다.

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((a,b) => (a.last_nom > b.last_nom) ? 1 : ((b.last_nom > a.last_nom) ? -1 : 0)); 

441
또는 인라인 : objs.sort (function (a, b) {return (a.last_nom> b.last_nom)? 1 : ((b.last_nom> a.last_nom)? -1 : 0);});
Marco Demaio


176
return a.last_nom.localeCompare(b.last_nom)작동합니다.
Cerbrus

146
필드가 숫자 인 정렬을 찾는 사람들을 위해, 비교 함수 본문 : return a.value - b.value;(ASC)
Andre Figueiredo

20
@Cerbrus localeCompare는 외국어에서 강조 문자를 사용할 때 중요하며 더욱 우아합니다.
Marcos Lima

839

전달한 값을 기준으로 객체를 정렬하는 동적 정렬 함수를 만들 수도 있습니다.

function dynamicSort(property) {
    var sortOrder = 1;
    if(property[0] === "-") {
        sortOrder = -1;
        property = property.substr(1);
    }
    return function (a,b) {
        /* next line works with strings and numbers, 
         * and you may want to customize it to your needs
         */
        var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
        return result * sortOrder;
    }
}

따라서 다음과 같은 객체 배열을 가질 수 있습니다.

var People = [
    {Name: "Name", Surname: "Surname"},
    {Name:"AAA", Surname:"ZZZ"},
    {Name: "Name", Surname: "AAA"}
];

... 그리고 당신이 할 때 작동합니다 :

People.sort(dynamicSort("Name"));
People.sort(dynamicSort("Surname"));
People.sort(dynamicSort("-Surname"));

실제로 이것은 이미 질문에 대답합니다. 아래 부분은 많은 사람들이 저에게 연락 하여 여러 매개 변수로 작동하지 않는다고 불평했기 때문에 작성되었습니다 .

여러 매개 변수

아래 함수를 사용하여 여러 정렬 매개 변수가있는 정렬 함수를 생성 할 수 있습니다.

function dynamicSortMultiple() {
    /*
     * save the arguments object as it will be overwritten
     * note that arguments object is an array-like object
     * consisting of the names of the properties to sort by
     */
    var props = arguments;
    return function (obj1, obj2) {
        var i = 0, result = 0, numberOfProperties = props.length;
        /* try getting a different result from 0 (equal)
         * as long as we have extra properties to compare
         */
        while(result === 0 && i < numberOfProperties) {
            result = dynamicSort(props[i])(obj1, obj2);
            i++;
        }
        return result;
    }
}

다음과 같이 할 수 있습니다.

People.sort(dynamicSortMultiple("Name", "-Surname"));

서브 클래 싱 배열

기본 객체를 확장 할 수있는 ES6을 사용할 수있는 사용자에게는 운이 좋을 것입니다.

class MyArray extends Array {
    sortBy(...args) {
        return this.sort(dynamicSortMultiple.apply(null, args));
    }
}

그것은 이것을 가능하게 할 것입니다 :

MyArray.from(People).sortBy("Name", "-Surname");

JavaScript의 속성 이름은 임의의 문자열이 될 수 있으며 "-"로 시작하는 속성이있는 경우 ( 아마도 좋지 않은 아이디어 일 수 있음) dynamicSort 함수를 수정하여 다른 것을 역 정렬로 사용해야합니다. 지시자.
Ege Özcan

dynamicSort()위의 예에서 대문자는 소문자보다 대문자를 먼저 사용 한다는 것을 알았 습니다. 나는 값이있는 경우 예를 들어, APd, Aklin,와 Abe- ASC에서 결과를 정렬해야한다 Abe, Aklin, APd. 하지만 당신의 예제의 결과는 APd, Abe, Aklin. 어쨌든이 동작을 수정 하시겠습니까?
Lloyd Banks

6
@LloydBanks 문자열에만 엄격하게 사용 var result = a[property].localeCompare(b[property]);하는 경우 대신 대신 사용할 수 있습니다 var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;.
Ege Özcan

1
@ EgeÖzcan 그것은 하나, 여기의 구현은 내가 사용 결국 한 맨 위 또는 맨 아래에 항목을 넣어해야 pastebin.com/g4dt23jU을
dzh

1
이것은 훌륭한 솔루션이지만 숫자를 비교하면 한 가지 문제가 있습니다. 확인하기 전에 이것을 추가하십시오 :if( !isNaN(a[property]) ) a[property] = Number(a[property]); if( !isNaN(b[property]) ) b[property] = Number(b[property]);
Ivijan Stefan Stipić

414

ES6 / ES2015 이상에서 다음과 같이 할 수 있습니다.

objs.sort((a, b) => a.last_nom.localeCompare(b.last_nom));

ES6 / ES2015 이전

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

29
이것은 JS 1.1 이후 사용 가능했으며, 여기에 지방 화살표 조각은 ES6 / 2015 조각입니다. 하지만 여전히 매우 유용합니다, 내 생각에 가장 좋은 대답
존 하딩

13
@PratikKelwalkar : 역전이 필요하면 a와 b 비교를 전환하십시오 : objs.sort ((a, b) => b.last_nom.localeCompare (a.last_nom));
Vlad Bezden

정렬을 위해 필드를 지정하기 위해 색인을 사용할 수도 있습니까? last_nom배열의 숫자 만 사용하는 것이 아니라 1?
and bri

4
@VladBezden 답변 주셔서 감사합니다! 이 솔루션은 매우 작은 프로그래밍 노력과 올바른 정렬 결과 및 [ "Name1", "Name10", "Name2", "something", "Name11"]과 같은 문자열 배열을 가진 첫 번째 솔루션입니다. 내가 제대로 작동하려면 정렬있어objs.sort((a, b) => a.last_nom.localeCompare(b.last_nom, undefined, {numberic: true}));
scipper

1
내림차순으로이 작업을 수행하려면 .sort ((a, b) => b.numberProperty-a.numberProperty). 오름차순 : .sort ((a, b) => a.numberProperty-b.numberProperty)
Sebastian Patten

188

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

18
데이비드, 당신은 대답을 편집 할 수 있습니까 var sortedObjs = _.sortBy( objs, 'first_nom' );? objs이 결과로 자체 정렬 되지 않습니다 . 기능은 정렬 된 배열 반환 합니다. 그것은 더 명백해질 것입니다.
Jess

10
역순 정렬 :var reverseSortedObjs = _.sortBy( objs, 'first_nom' ).reverse();
Erdal G.

2
자바 스크립트 라이브러리 "밑줄"을로드해야합니다.<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"> </script>
and-bri

5
Lodash그 중 하나를 선호하는 사람들 도 이용할 수 있습니다
WoJ

2
lodash에서 이것은 동일 var sortedObjs = _.sortBy( objs, 'first_nom' );하거나 다른 순서로 원하는 경우 :var sortedObjs = _.orderBy( objs, ['first_nom'],['dsc'] );
Travis Heeter

186

사람들이 왜 그렇게 복잡하게 만들지 마십시오.

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

알파벳 역순으로 정렬되도록 연산자를 교체하십시오.


17
sort에 사용 된 함수가 -1, 0 또는 1을 리턴해야하므로 위의 함수는 부울을 리턴하므로 실제로 올바르지 않습니다. 크롬에서는 잘 작동하지만 PhantomJS에서는 실패합니다. 참조 code.google.com/p/phantomjs/issues/detail?id=1090
schup

일부 엔진은 어리 석음을 설명하는데, 이런 식으로 그것을 악용했습니다. 답장을 올바른 버전으로 업데이트했습니다.
p3lim

19
첫 번째 버전을 꺼내기 위해 편집을 제안합니다. 더 간결하므로 매력적으로 보이지만 적어도 안정적으로 작동하지는 않습니다. 누군가가 하나의 브라우저에서 시도하고 작동하면 문제가 있음을 깨닫지 못할 수도 있습니다 (특히 주석을 읽지 않은 경우). 두 번째 버전은 제대로 작동하므로 첫 번째 버전은 실제로 필요하지 않습니다.
Kate

2
@Simon 나는 "약간 잘못된"버전을 먼저 사용하는 것에 대해 매우 감사했다. 더 엄격한 구현은 구문 분석하고 이해하는 데 몇 초가 걸리고 그것 없이는 훨씬 더 어려울 것이기 때문이다.
Aaron Sherman

1
@ Lion789 그냥 이렇게 :if(a.count == b.count) return a.name > b.name; else return a.count > b.count;
p3lim

62

성이 중복되는 경우 이름별로 정렬 할 수 있습니다.

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

-1 또는 1을 반환하는 것은 무엇을 의미합니까? 나는 -1이 문자 그대로 A가 B보다 작다는 것을 의미한다는 것을 이해하지만, 왜 1 또는 -1을 사용합니까? 모든 사람들이 그 숫자를 반환 값으로 사용하고 있지만 왜 그럴까요? 감사.
Chris22

1
@ Chris22는 음수가 반환 되면 배열에서 b와야 함을 의미합니다 a. 양수가 반환되면 a뒤에옵니다 b. 경우 0반환, 그것은 그들이 동일한 것으로 간주됩니다 것을 의미합니다. 당신은 항상 다음 문서를 읽을 수 있습니다 : developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
BadFeelingAboutThis

@BadFeelingAbout 설명과 링크에 감사드립니다. 믿거 나 말거나, 1, 0, -1여기에 요청하기 전에 다양한 코드 스 니펫을 봤습니다. 방금 필요한 정보를 찾지 못했습니다.
Chris22

48

프로토 타입 상속을 사용하여이 문제에 대한 간단하고 빠른 솔루션 :

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

업데이트 : 더 이상 원래 배열을 수정하지 않습니다.


5
다른 배열을 반환하지 않습니다. 그러나 실제로 원래를 정렬합니다!.
Vinay Aggarwal

숫자 (예 : 0,1,2,10,11 등)와 함께 자연 정렬을 사용하려면 Radise 세트와 함께 parseInt를 사용하십시오. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… so : return (parseInt (a [p], 10)> parseInt (b [p], 10))? 1 : (parseInt (a [p], 10) <parseInt (b [p], 10))? -1 : 0;
Paul

@codehuntr 수정 해 주셔서 감사합니다. 그러나이 감도를 수행하기 위해 정렬 기능을 만드는 대신 데이터 유형을 수정하기 위해 별도의 기능을 만드는 것이 좋습니다. 정렬 함수는 어떤 속성에 어떤 종류의 데이터가 포함 될지 알 수 없기 때문입니다. :)
Vinay Aggarwal

아주 좋아요 화살표를 뒤집 으면 상승 / 하강 효과가 나타납니다.
압둘 사딕 얄친

4
절대로 핵심 객체의 프로토 타입을 수정하는 솔루션을 제안하지 마십시오
pbanka

39

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

7
질문에서 문자열은 숫자가 아닌 비교를 위해 사용되었습니다. 귀하의 답변은 숫자로 정렬하는 데 효과적이지만 문자열로 비교하는 것은 좋지 않습니다.
smcstewart

a.value - b.value개체의 특성 (비교하는 데 사용할 이 경우는) 데이터의 다양한 시간에 채택 될 수있다. 예를 들어, 정규식을 사용하여 인접한 문자열 의 각 쌍을 비교할 수 있습니다 .
0leg

1
@ 0leg 여기에서 정규식을 사용하여 문자열을 비교하는 예를보고 싶습니다.
Bob Stein

이 구현은 ID별로 정렬 해야하는 경우 매우 좋습니다. 예, 정규식을 사용하여 주변 문자열을 비교하여 솔루션을보다 복잡하게 만드는 반면 정규식을 주어진 솔루션과 함께 사용하면이 단순화 된 버전의 목적이 그렇지 않습니다. 단순성이 최고입니다.
surendrapanday 2014

33

틀린 정답 :

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

최신 정보

Beauchamp의 의견에서 :

arr.sort((a, b) => a.name < b.name ? -1 : (a.name > b.name ? 1 : 0))

더 읽기 쉬운 형식 :

arr.sort((a, b) => {
  if (a.name < b.name) return -1
  return a.name > b.name ? 1 : 0
})

중첩 된 삼항이없는 경우 :

arr.sort((a, b) => a.name < b.name ? - 1 : Number(a.name > b.name))

설명 : Number()시전됩니다 true1false0.


작동하지만 어떤 이유로 결과가 불안정합니다.
TitanFighter

@ AO17 아니오. 문자열을 뺄 수 없습니다.
패트릭 로버츠

15
arr.sort((a, b) => a.name < b.name ? -1 : (a.name > b.name ? 1 : 0))
Jean-François Beauchamp

3
@ Jean-FrançoisBeauchamp, 귀하의 솔루션은 완벽하고 훌륭하게 작동합니다.
Ahsan

숫자가있는 세 번째 것은 간단하고 훌륭합니다!
코조

29

사용자 정의 비교 함수를 사용하는 대신 사용자 정의 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();

29

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

이제 _.property 속기 user.age를 사용하여 일치해야하는 속성의 경로를 지정할 수 있습니다. 중첩 된 연령 속성을 기준으로 사용자 개체를 정렬합니다. 예, 중첩 속성 일치가 가능합니다!

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

역전을 원하십니까? 문제 없어요. _.reverse를 사용하십시오 .

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

체인을 사용하여 둘 다 결합하고 싶 습니까?

const { chain } = require('lodash');
const sortedObjs = chain(users).sortBy('user.age').reverse().value();

또는 언제 체인을 통한 흐름 을 선호합니까

const { flow, reverse, sortBy } = require('lodash/fp');
const sortedObjs = flow([sortBy('user.age'), reverse])(users); 

28

당신이 사용할 수있는

가장 쉬운 방법 : Lodash

( https://lodash.com/docs/4.17.10#orderBy )

이 메소드는 _.sortBy와 유사하지만 반복 할 정렬 순서를 지정하여 정렬 할 수 있습니다. 주문을 지정하지 않으면 모든 값이 오름차순으로 정렬됩니다. 그렇지 않으면, 내림차순은 "desc", 해당 값의 오름차순은 "asc"의 순서를 지정하십시오.

인수

collection (Array | Object) : 반복 할 컬렉션. [iteratees = [_. identity]] (Array [] | 함수 [] | Object [] | string []) : 정렬을 반복합니다. [orders] (string []) : 반복 순서입니다.

보고

(배열) : 새로운 정렬 된 배열을 반환합니다.


var _ = require('lodash');
var homes = [
    {"h_id":"3",
     "city":"Dallas",
     "state":"TX",
     "zip":"75201",
     "price":"162500"},
    {"h_id":"4",
     "city":"Bevery Hills",
     "state":"CA",
     "zip":"90210",
     "price":"319250"},
    {"h_id":"6",
     "city":"Dallas",
     "state":"TX",
     "zip":"75000",
     "price":"556699"},
    {"h_id":"5",
     "city":"New York",
     "state":"NY",
     "zip":"00010",
     "price":"962500"}
    ];

_.orderBy(homes, ['city', 'state', 'zip'], ['asc', 'desc', 'asc']);

23

여기에는 많은 좋은 답변이 있지만 훨씬 더 복잡한 정렬을 달성하기 위해 매우 간단하게 확장 할 수 있음을 지적하고 싶습니다. OR 연산자를 사용하여 비교 함수를 다음과 같이 연결하면됩니다.

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

어디 fn1,fn2 ...은 [-1,0,1]을 반환하는 정렬 함수입니다. 결과적으로 "fn1로 정렬", "fn2로 정렬"은 SQL의 ORDER BY와 거의 같습니다.

이 솔루션은 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는 외부 라이브러리 나 복잡한 코드 없이도 먼 길을 갈 수 있다는 것입니다. 문자열 구문 분석을 수행 할 필요가 없으므로 매우 효과적입니다.


23

사용법 예 :

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}
 */
const 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.
  const 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.
  const moveLarger = reverse ? -1 : 1;

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

이것을 분류 해 주셔서 감사합니다 1, 0, -1. 정렬 순서에 숫자 가 사용되는 이유를 이해하려고합니다 . 위의 설명에도 불구하고 매우 좋아 보입니다. 아직 이해하지 못합니다. 항상 -1배열 길이 속성을 사용할 때 와 같이 생각 합니다. 즉 arr.length = -1, 항목을 찾을 수 없음을 의미합니다. 아마 여기에 것들을 섞어 놓고 있지만 1, 0, -1순서를 결정하는 데 숫자 가 사용되는 이유를 이해하도록 도와 줄 수 있습니까? 감사.
Chris22

1
이것은 완전히 정확하지는 않지만 다음과 같이 생각하면 도움이 될 수 있습니다. array.sort에 전달 된 함수는 배열의 각 항목에 대해 "a"라는 인수로 한 번 호출됩니다. 각 함수 호출의 반환 값은 다음 항목 "b"와 비교하여 "a"항목의 인덱스 (현재 위치 번호)를 변경하는 방법입니다. 인덱스는 배열의 순서를 지시합니다 (0, 1, 2 등). 만약 "a"가 인덱스 5에 있고 -1을 반환하면 5 + -1 == 4를 반환합니다 (앞쪽으로 이동) 5 + 0 == 5 (그것을 그대로 유지하십시오) 등등. 그것은 정렬 된 배열을 남겨두고 끝까지 도달 할 때마다 매번 2 개의 이웃을 비교하는 배열을 걷습니다.
Jamie Mason

자세한 설명을 위해 시간을 내 주셔서 감사합니다. 그래서 당신의 설명과 사용 MDN Array.prototype.sort을 비교 : 나는이 생각하고 무엇을 말해주지 a하고 b있는 경우, a보다 큰 b의 인덱스에 추가 한 a뒤에 장소를 b하는 경우, a이하입니다 b에서 1을 빼고 a앞에 배치합니다 b. ab같은 경우 0을 더한 다음 a그대로 두십시오.
Chris22

22

그래서 여기에 내가 모두 그 작품 사용하려면 간결한 비교 방법의 제안이 특정 접근을 보지 못했다 stringnumber:

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) => {
  const fa = fn(a);
  const fb = fn(b);
  return -(fa < fb) || +(fa > fb);
};

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) => {
  const fa = fn(a);
  const fb = fn(b);
  return -(fa < fb) || +(fa > fb);
};

그들을 비교합니다.

이를 기억해 fn = o => o.last_nom비교 함수를 등가로 확장 할 수 있습니다.

(a, b) => {
  const fa = a.last_nom;
  const fb = b.last_nom;
  return -(fa < fb) || +(fa > fb);
};

논리 OR ||연산자에는 단락 기능이있어 여기서 매우 유용합니다. 작동 방식으로 인해 위의 함수 본문은

if (fa < fb) return -1;
if (fa > fb) return 1;
return 0;

추가 보너스로, 여기에 화살표 기능이없는 ECMAScript 5의 기능이 있습니다. 불행히도 더 자세한 내용은 다음과 같습니다.

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) {
    var fa = fn(a);
    var fb = fn(b);
    return -(fa < fb) || +(fa > fb);
  };
};

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

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


17

나는이 질문이 너무 오래되었다는 것을 알고 있지만 내 구현과 비슷한 구현을 보지 못했습니다.
이 버전은 Schwartzian 변환 관용구를 기반으로합니다 .

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: 'Mashraki',          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'));

14

복잡한 객체 배열 정렬 (추가)

이 배열과 같은 더 복잡한 데이터 구조가 발생할 수 있으므로 솔루션을 확장 할 것입니다.

TL; DR

더 플러그 버전을 기반으로 @ EGE-Özcan '매우 사랑이야 대답 .

문제

아래에서 발생하여 변경할 수 없습니다. 또한 객체를 일시적으로 평평하게하고 싶지 않았습니다. 또한 주로 성능상의 이유와 직접 구현하는 재미 때문에 밑줄 / 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에


2
왜? 이것은 원래 질문에 대한 대답이 아니며 "목표"는 People.sort ((a, b) => {return a.Name.name.localeCompare (b.Name.name) || a.Name으로 간단히 해결할 수 있습니다. .surname.localeCompare (b.Name.surname)})
Tero Tolonen

12

하나 더 옵션 :

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

기본적으로 오름차순으로 정렬합니다.


1
필요한 경우 약간 여기에 여러 필드를 기준으로 정렬 버전입니다 변경 : stackoverflow.com/questions/6913512/...
라브 샨 Samandarov

다음 함수가 될 것 같습니다 : export function generateSortFn (prop : string, reverse : boolean = false) : (... args : any) => number {return (a, b) => {return a [prop ] <b [prop]? 역전 ? 1 : -1 : a [prop]> b [prop]? 역전 ? -1 : 1 : 1; }; }
Den Kerny

가장 짧은 코드보다 더 읽기 쉬운 코드를 선호합니다.
Ravshan Samandarov

동의하지만 어떤 경우에는 유틸리티 기능을 볼 필요가 없습니다.
Den Kerny

11

속성으로 객체 배열을 정렬하는 간단한 함수

function sortArray(array, property, direction) {
    direction = direction || 1;
    array.sort(function compare(a, b) {
        let comparison = 0;
        if (a[property] > b[property]) {
            comparison = 1 * direction;
        } else if (a[property] < b[property]) {
            comparison = -1 * direction;
        }
        return comparison;
    });
    return array; // Chainable
}

용법:

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

sortArray(objs, "last_nom"); // Asc
sortArray(objs, "last_nom", -1); // Desc

이 솔루션은 양방향 정렬에 완벽하게 작동했습니다. 감사합니다
manjuvreddy

10

간단한 방법 :

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

'.toLowerCase()'현을 비교할 때 침식을 방지하기 위해 필요한 것을 참조하십시오 .


4
화살표 기능 을 사용 하여 코드를 좀 더 우아하게 만들 수 있습니다 .objs.sort( (a,b) => b.last_nom.toLowerCase() < a.last_nom.toLowerCase() );
Sertage

여기 설명 된 것과 같은 이유로 잘못되었습니다 .
패트릭 로버츠

2
화살표 기능은 ES5에 적합하지 않습니다. 엔진 톤은 여전히 ​​ES5로 제한되어 있습니다. 필자의 경우 ES5 엔진을 사용하고 있기 때문에 위의 답변이 훨씬 더 좋습니다.
dylanh724

9

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

9

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

1
아이디어 주셔서 감사합니다! 그건 그렇고, 사람들이 배열 프로토 타입을 변경하도록 권장하지 마십시오 (내 예제의 끝 부분에있는 경고 참조).
Ege Özcan

8

예를 들어 두 개의 필드 (성, 이름)가 아닌 하나의 필드로 정렬해야합니다. Alasql 라이브러리를 사용 하여 한 줄로 정렬 할 수 있습니다 .

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

jsFiddle 에서이 예제 시도하십시오 .


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

1
실제로 작동하지 않는 것 같고 허용 된 대답을 사용해야했습니다. 올바르게 정렬되지 않았습니다.
madprops

8

원래 예를 들면 다음과 같습니다.

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;

8

이 시도,

UPTO ES5

//Ascending Sort
items.sort(function (a, b) {
   return a.value - b.value;
});


//Descending Sort
items.sort(function (a, b) {
   return b.value - a.value;
});


IN ES6 & above:

// Ascending sort
items.sort((a, b) => a.value - b.value);

// Descending Sort
 items.sort((a, b) => b.value - a.value);

가장 쉽고 간편한 솔루션
Omar Hasan

7

혼동을 막기 위해 소문자로 변환해야 할 수도 있습니다.

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

})

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

1
코드의 기능과 문제를 해결하는 이유에 대한 설명을 추가하려면 게시물을 수정하십시오. 작동하는 경우에도 대부분 코드 만 포함 된 답변은 OP가 문제를 이해하는 데 도움이되지 않습니다.
Drenmi

7

Ramda를 사용하여

npm 설치 람다

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)

6

이것은 단순한 문제이며 사람들이 왜 그렇게 복잡한 해결책을 가지고 있는지 모릅니다.
간단한 정렬 기능 ( 빠른 정렬 알고리즘 기반 ) :

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

5
js에서 빠른 정렬을 구현하는 간단한 방법은 무엇입니까? 간단한 알고리즘이지만 간단한 솔루션은 아닙니다.
앤드류

외부 라이브러리를 사용하지 않고 객체의 프로토 타입을 변경하지 않기 때문에 간단합니다. 제 생각에는, 코드의 길이는 코드의 복잡성에 직접적인 영향이없는
길 Epshtain

2
글쎄, 다른 말로 시도해 보자. 어떻게 바퀴를 재창조하는 것이 간단한 해결책인가?
Roberto14
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.