JavaScript에서 문자열을 정렬하는 방법


344

attr문자열 유형 의 필드 를 기준으로 정렬하려는 객체 목록이 있습니다 . 나는 사용하려고-

list.sort(function (a, b) {
    return a.attr - b.attr
})

하지만 발견 -자바 스크립트 문자열 작업에 표시되지 않습니다. 문자열 유형의 속성을 기반으로 객체 목록을 정렬하려면 어떻게해야합니까?


1
JavaScript case insensitive string comparisonstackoverflow.com/questions/2140627/...
아드 리앙은 수

빠른 "국제화 된"솔루션의 경우 (세계의 일부 액센트를 다룰 수는 없기 때문에 부분적으로 만 추측 할 수 있습니다) 악센트를 무시하고, 즉 제거 할 수 있습니다. 그런 다음 문자열 비교 Javascript : remove accents/diacritics in strings
만하십시오

2
Jeff Atwood 자신도 2007 년에이 일반적인 문제에 대한 블로그 게시물을 작성했습니다. blog.codinghorror.com/sorting-for-humans-natural-sort-order
Adrien Be

답변:


621

String.prototype.localeCompare귀하의 예를 사용하십시오 :

list.sort(function (a, b) {
    return ('' + a.attr).localeCompare(b.attr);
})

예외를 피하기 위해 a.attr을 문자열로 만듭니다. Internet Explorer 6 및 Firefox 1 부터localeCompare 지원되었습니다 . 로캘과 관련이없는 다음 코드가 사용 된 것을 볼 수도 있습니다.

if (item1.attr < item2.attr)
  return -1;
if ( item1.attr > item2.attr)
  return 1;
return 0;

81
다른 사람이 내가했던 것과 같은 성급한 실수를 저지르기 전에 localCompare가 아니라 local e Compare입니다.
ento

12
첫 번째 솔루션은 문자 ASCII 값을 비교할 때 "A"가 "z"뒤에 있지만 "Z"앞에 오는 것으로 간주합니다. localeCompare()이 문제에 부딪치지 않지만 숫자를 이해하지 못하므로 대부분의 언어에서 정렬 비교와 마찬가지로 [ "1", "10", "2"]가 표시됩니다. UI 프런트 엔드를 기준으로 정렬하려면 alphanum / natural 정렬 알고리즘 stackoverflow.com/questions/4340227/… 또는 stackoverflow.com/questions/4321829/…
Dead.Rabit를

2
참고 localeCompare()최신 브라우저에서 지원됩니다 IE11 +를 글을 쓰는 시점은 참조 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
아드는 수

3
아니요, 나는 표의 첫 줄을 의미합니다. @Adrien-IE는 localeCompare()많은 버전으로 돌아가는 것을 지원하지만 버전 11까지는 로캘 지정을 지원하지 않습니다 . Dead.Rabit과 관련된 질문도 참고하십시오.
Shog9

3
@ Shog9 내 나쁜, IE6부터 지원되는 것 같습니다! msdn.microsoft.com/en-us/library/ie/s4esdbwz(v=vs.94).aspx 에서 (스크롤 다운 / 검색 localeCompare () 메서드)을 참조 하십시오 . 한 가지 주목할 점은 로케일 및 옵션 인수 (IE11 이전에 사용 된 인수)를 사용하지 않는 이전 구현에서 사용 된 로케일 및 정렬 순서는 구현에 따라 다릅니다. 즉 , Firefox, Safari, Chrome 및 IE는 문자열을 같은 순서로 정렬하지 마십시오. 참조 code.google.com/p/v8/issues/detail?id=459
아드는 수

166

업데이트 된 답변 (2014 년 10 월)

나는이 문자열 자연 정렬 순서에 대해 정말로 화가 났기 때문에이 문제를 조사하는 데 꽤 시간이 걸렸습니다. 이게 도움이 되길 바란다.

긴 이야기 짧음

localeCompare()문자 지원이 잘못되었습니다. 그냥 사용하십시오. 에서 지적한 것처럼 Shog9귀하의 질문에 대한 답변은 다음과 같습니다.

return item1.attr.localeCompare(item2.attr);

모든 사용자 정의 자바 스크립트 "자연 문자열 정렬 순서"구현에서 발견 된 버그

"자연 문자열 정렬 순서"라고하는 더 정확하게 문자열 비교를 시도하는 많은 사용자 정의 구현이 있습니다.

이러한 구현으로 "재생"할 때 항상 이상한 "자연 정렬 순서"선택 또는 실수 (또는 최상의 경우 생략)를 발견했습니다.

일반적으로 특수 문자 (공백, 대시, 앰퍼샌드, 괄호 등)는 올바르게 처리되지 않습니다.

그런 다음 다른 위치에 혼합되어 나타나는 것으로 나타났습니다. 일반적으로 다음과 같습니다.

  • 일부는 대문자 'Z'와 소문자 'a'사이에 있습니다.
  • 일부는 '9'와 대문자 'A'사이에 있습니다.
  • 일부는 소문자 'z'뒤에 올 것입니다

공백 문자를 제외하고 특수 문자가 모두 한곳에서 "그룹화"될 것으로 예상 한 경우 (항상 첫 문자 임). 즉, 숫자 앞 또는 숫자와 문자 사이의 모든 문자 (소문자와 대문자는 "함께"함께 ")이거나 문자 뒤에 있습니다.

내 결론은 간신히 특이한 문자 (예 : 대시, 느낌표 등의 발음 부호가있는 문자)를 추가하기 시작할 때 모두 일관성있는 순서를 제공하지 못한다는 것입니다.

맞춤형 구현에 대한 연구 :

를 통해 브라우저의 기본 "자연 문자열 정렬 순서"구현 localeCompare()

localeCompare()가장 오래된 구현 (로캘 및 옵션 인수가없는)은 IE6 +에서 지원됩니다. http://msdn.microsoft.com/en-us/library/ie/s4esdbwz (v = vs.94) .aspx (localeCompare ( ) 방법). 내장 된 localeCompare()방법은 국제 및 특수 문자까지 정렬에서 훨씬 더 잘 작동합니다. 이 localeCompare()방법을 사용하는 유일한 문제점 은 "사용 된 로케일 및 정렬 순서가 전적으로 구현에 의존적"이라는 것입니다. 즉, stringOne.localeCompare (stringTwo)와 같은 localeCompare를 사용하는 경우 : Firefox, Safari, Chrome 및 IE는 문자열의 정렬 순서가 다릅니다.

브라우저 고유 구현에 대한 연구 :

"문자열 자연 정렬 순서"의 어려움

견고한 알고리즘을 구현하는 것 (즉, 일관성은 있지만 광범위한 문자를 포함 함)은 매우 어려운 작업입니다. UTF8은 포함 2000 개 이상의 문자커버 120 명 이상의 스크립트 (언어) . 마지막으로이 작업에 대한 일부 사양이 있으며 "Unicode Collation Algorithm"이라고하며 http://www.unicode.org/reports/tr10/에 있습니다. /software/257286/is-there-any-language-agnostic-specification-for-string-natural-sorting-order에 게시 된이 질문에 대한 자세한 내용을 찾을 수 있습니다

최종 결론

따라서 내가 만난 자바 스크립트 사용자 정의 구현에서 제공하는 현재 수준의 지원을 고려할 때 아마도이 모든 문자 및 스크립트 (언어)를 지원하는 데 아무런 도움이되지 않을 것입니다. 따라서 브라우저의 기본 localeCompare () 메서드를 사용하고 싶습니다. 그렇습니다. 브라우저에서 일관성이없는 단점이 있지만 기본 테스트에서는 훨씬 넓은 범위의 문자를 포함하여 견고하고 의미있는 정렬 순서를 허용합니다.

에서 지적했듯이 Shog9귀하의 질문에 대한 답변은 다음과 같습니다.

return item1.attr.localeCompare(item2.attr);

더 읽을 거리 :

내가 믿는 "올바른"방향으로 나를 안내하는 Shog9의 훌륭한 답변 덕분에


38

답변 (현대 ECMAScript에서)

list.sort((a, b) => (a.attr > b.attr) - (a.attr < b.attr))

또는

list.sort((a, b) => +(a.attr > b.attr) || -(a.attr < b.attr))

기술

부울 값을 숫자로 캐스팅하면 다음이 생성됩니다.

  • true -> 1
  • false -> 0

세 가지 가능한 패턴을 고려하십시오.

  • x는 y보다 큽니다 : (x > y) - (y < x)-> 1 - 0->1
  • x는 y와 같습니다 (x > y) - (y < x).-> 0 - 0->0
  • x는 y보다 작습니다 : (x > y) - (y < x)-> 0 - 1->-1

(대체)

  • x는 y보다 큽니다 : +(x > y) || -(x < y)-> 1 || 0->1
  • x는 y와 같습니다 +(x > y) || -(x < y).-> 0 || 0->0
  • x는 y보다 작습니다 : +(x > y) || -(x < y)-> 0 || -1->-1

따라서 이러한 논리는 일반적인 정렬 비교기 기능과 동일합니다.

if (x == y) {
    return 0;
}
return x > y ? 1 : -1;

1
이 트릭을 사용한 이전 답변 에 대해 언급 했듯이 코드 전용 답변은 작동 방식을 설명하여 더 유용 할 수 있습니다.
Dan Dascalescu

추가 설명
mpyw

이것이 localeCompare보다 낫거나 나쁜지에 대해 언급 할 수 있습니까?
Ran Lottem

3
@ RanLottem localeCompare과 표준 비교는 다른 결과를 산출합니다. 어느 것을 기대하십니까? 코드 포인트 순서 ["A", "b", "C", "d"].sort((a, b) => a.localeCompare(b))대로 수행하는 동안 대소 문자를 구분하지 않는 알파벳 순서로 ["A", "b", "C", "d"].sort((a, b) => (a > b) - (a < b))정렬
mpyw

나는 그것이 주요한 고집 포인트 인 것처럼 보인다. 성능 차이에 대한 아이디어가 있습니까?
Ran Lottem

13

여기서는> 또는 <와 ==를 사용해야합니다. 따라서 해결책은 다음과 같습니다.

list.sort(function(item1, item2) {
    var val1 = item1.attr,
        val2 = item2.attr;
    if (val1 == val2) return 0;
    if (val1 > val2) return 1;
    if (val1 < val2) return -1;
});

1
참고로, 이것은 문자열 대 숫자 비교를 처리하지 않습니다. 예 : 'Z'<9 (거짓), 'Z'> 9 (또한 거짓 ??), 'Z'== 9 (또한 거짓 !!). JavaScript의 Silly NaN ...
Kato

7

중첩 된 삼항 화살표 기능

(a,b) => (a < b ? -1 : a > b ? 1 : 0)

7

문자열은 자바 스크립트에서 직접 비교할 수 있기 때문에이 작업을 수행합니다.

list.sort(function (a, b) {
    return a.attr > b.attr ? 1: -1;
})

정렬 함수에서 빼기는 알파벳이 아닌 (숫자) 정렬이 필요한 경우에만 사용되며 물론 문자열에서는 작동하지 않습니다.


6

나는 이것에 대해 오랫동안 귀찮게 했으므로 마침내 이것을 연구하고 사물이 왜 그런지에 대한 긴 바람의 이유를 알려줍니다.

로부터 사양 :

Section 11.9.4   The Strict Equals Operator ( === )

The production EqualityExpression : EqualityExpression === RelationalExpression
is evaluated as follows: 
- Let lref be the result of evaluating EqualityExpression.
- Let lval be GetValue(lref).
- Let rref be the result of evaluating RelationalExpression.
- Let rval be GetValue(rref).
- Return the result of performing the strict equality comparison 
  rval === lval. (See 11.9.6)

이제 11.9.6으로갑니다

11.9.6   The Strict Equality Comparison Algorithm

The comparison x === y, where x and y are values, produces true or false. 
Such a comparison is performed as follows: 
- If Type(x) is different from Type(y), return false.
- If Type(x) is Undefined, return true.
- If Type(x) is Null, return true.
- If Type(x) is Number, then
...
- If Type(x) is String, then return true if x and y are exactly the 
  same sequence of characters (same length and same characters in 
  corresponding positions); otherwise, return false.

그게 다야. 인수가 정확히 동일한 문자열 (해당 위치의 길이와 문자가 동일) 인 경우 트리플 등호 연산자는 문자열에 적용됩니다.

따라서 ===다른 소스에서 온 문자열을 비교하려고 할 때 작동하지만 결국 코드의 인라인 문자열에 대한 일반적인 시나리오 인 동일한 값을 갖게됩니다. 예를 들어,이라는 변수가 있고 connection_state현재 다음 중 어느 상태인지 알고 자하는 경우 ['connecting', 'connected', 'disconnecting', 'disconnected']직접 사용할 수 있습니다.=== .

그러나 더 있습니다. 11.9.4 바로 위에 간단한 메모가 있습니다.

NOTE 4     
  Comparison of Strings uses a simple equality test on sequences of code 
  unit values. There is no attempt to use the more complex, semantically oriented
  definitions of character or string equality and collating order defined in the 
  Unicode specification. Therefore Strings values that are canonically equal
  according to the Unicode standard could test as unequal. In effect this 
  algorithm assumes that both Strings are already in normalized form.

흠. 지금 무엇? 외부 적으로 얻은 줄은 이상한 유니 코드 일 수 있으며 아마도 우리는 온화 ===하게 정의하지 않습니다. localeCompare구조에 온다 :

15.5.4.9   String.prototype.localeCompare (that)
    ...
    The actual return values are implementation-defined to permit implementers 
    to encode additional information in the value, but the function is required 
    to define a total ordering on all Strings and to return 0 when comparing
    Strings that are considered canonically equivalent by the Unicode standard. 

우리는 지금 집에 갈 수 있습니다.

tl; dr;

자바 스크립트에서 문자열을 비교하려면 localeCompare; 예를 들어 내부 프로그램 상수이기 때문에 문자열에 비 ASCII 구성 요소가없는 경우 ===에도 작동합니다.


0

초기 질문의 작업에서 다음 작업을 수행하고 있습니다.

item1.attr - item2.attr

따라서이 숫자가 숫자라고 가정하면 (예 : item1.attr = "1", item2.attr = "2") 유형을 보장하는 경우에도 "==="연산자 (또는 기타 엄격한 평가자)를 사용할 수 있습니다. 다음이 작동합니다.

return parseInt(item1.attr) - parseInt(item2.attr);

이들이 영숫자이면 localCompare ()를 사용하십시오.


0
list.sort(function(item1, item2){
    return +(item1.attr > item2.attr) || +(item1.attr === item2.attr) - 1;
}) 

샘플 작동 방식 :

+('aaa'>'bbb')||+('aaa'==='bbb')-1
+(false)||+(false)-1
0||0-1
-1

+('bbb'>'aaa')||+('bbb'==='aaa')-1
+(true)||+(false)-1
1||0-1
1

+('aaa'>'aaa')||+('aaa'==='aaa')-1
+(false)||+(true)-1
0||1-1
0

3
작동 방식을 설명하면 코드 전용 답변을 더욱 유용하게 만들 수 있습니다.
Dan Dascalescu

-2
<!doctype html>
<html>
<body>
<p id = "myString">zyxtspqnmdba</p>
<p id = "orderedString"></p>
<script>
var myString = document.getElementById("myString").innerHTML;
orderString(myString);
function orderString(str) {
    var i = 0;
    var myArray = str.split("");
    while (i < str.length){
        var j = i + 1;
        while (j < str.length) {
            if (myArray[j] < myArray[i]){
                var temp = myArray[i];
                myArray[i] = myArray[j];
                myArray[j] = temp;
            }
            j++;
        }
        i++;
    }
    var newString = myArray.join("");
    document.getElementById("orderedString").innerHTML = newString;
}
</script>
</body>
</html>

1
이것이 어떻게 답변을 통해 질문을 해결할 수 있는지에 대한 정보를 추가하십시오. 코드 전용 답변은 환영하지 않습니다. 감사합니다.
wayneOS

여기서 문자열 내에서 문자를 주문하려고합니다. "Array.sort"를 사용하여이 정렬을 간단히 수행 할 수 있습니다. 예 : str.split ( ""). sort () .join ( "")
Alejadro Xalabarder

-2
var str = ['v','a','da','c','k','l']
var b = str.join('').split('').sort().reverse().join('')
console.log(b)

이 코드가 문제를 해결하는 방법과 이유에 대한 설명포함 하여 질문을 해결할 수는 있지만 게시물의 품질을 향상시키는 데 도움이되며 더 많은 투표를 할 수 있습니다. 지금 질문하는 사람뿐만 아니라 앞으로 독자들에게 질문에 대답하고 있음을 기억하십시오. 제발 편집 설명을 추가하고, 제한 및 가정이 적용 무엇의 표시를 제공하는 답변을.
데이브
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.