Javascript의 값으로 연관 배열을 정렬하는 방법은 무엇입니까?


84

연관 배열이 있습니다.

array["sub2"] = 1;
array["sub0"] = -1;
array["sub1"] = 0;
array["sub3"] = 1;
array["sub4"] = 0;

결과가 다음 순서로 각 인덱스가있는 배열이되는 값을 기준으로 정렬 (내림차순)하는 가장 우아한 방법은 무엇입니까?

sub2, sub3, sub1, sub4, sub0

1
객체 속성에는 언어 정의 순서가 없기 때문에 할 수 없습니다 (속성을 구현 한 특정 방식에 따라 일부 JS 엔진에서는 제외).
Quentin 2011 년

답변:


113

자바 스크립트는 당신이 생각하는 "연관 배열"이 없습니다. 대신 배열과 유사한 구문 (예제에서와 같이)을 사용하여 객체 속성을 설정하는 기능과 객체의 속성을 반복하는 기능이 있습니다.

이것의 결론은 속성을 반복 하는 순서 에 대한 보장이 없으므로 정렬과 같은 것은 없다는 것입니다. 대신 개체 속성을 "진정한"배열 (순서를 보장 함)로 변환해야합니다. 다음은 객체를 두 개의 튜플 (요소가 두 개인 배열)의 배열로 변환하고 설명하는대로 정렬 한 다음 반복하는 코드 조각입니다.

var tuples = [];

for (var key in obj) tuples.push([key, obj[key]]);

tuples.sort(function(a, b) {
    a = a[1];
    b = b[1];

    return a < b ? -1 : (a > b ? 1 : 0);
});

for (var i = 0; i < tuples.length; i++) {
    var key = tuples[i][0];
    var value = tuples[i][1];

    // do something with key and value
}

콜백을받는 함수로 래핑하는 것이 더 자연 스러울 수 있습니다.

function bySortedValue(obj, callback, context) {
  var tuples = [];

  for (var key in obj) tuples.push([key, obj[key]]);

  tuples.sort(function(a, b) {
    return a[1] < b[1] ? 1 : a[1] > b[1] ? -1 : 0
  });

  var length = tuples.length;
  while (length--) callback.call(context, tuples[length][0], tuples[length][1]);
}

bySortedValue({
  foo: 1,
  bar: 7,
  baz: 3
}, function(key, value) {
  document.getElementById('res').innerHTML += `${key}: ${value}<br>`
});
<p id='res'>Result:<br/><br/><p>


1
tuples.sort 함수는 tuples.sort (function (a, b) {return a [1]-b [1];});
stot

2
@stot — 만약 당신의 값이 모두 숫자라면 (asker의 예에서와 같이) 절대적으로. 나는 무심코 문자열과 함께 작동하는 비교 기능을 제공 한 것 같습니다. :-)
Ben Blank

@ 벤 : 당신이 바로, 제공되는 버전은 더 일반적이다 ;-)하는 예
특정 표적 장기 독성은

@Ben,이 게시물에 대해 대단히 감사합니다. 문자열 비교 기능과 관련하여 ASCII 값 비교를 사용합니까?
jjwdesign

@jjwdesign, 문자열이 인코딩되지 않았다고 가정하면 유니 코드 코드 포인트별로 정렬됩니다.
Ben Blank

85

'연관 배열'의 의미를 수정하는 대신 이것이 원하는 것이라고 생각합니다.

function getSortedKeys(obj) {
    var keys = keys = Object.keys(obj);
    return keys.sort(function(a,b){return obj[b]-obj[a]});
}

위해 정말 오래된 브라우저 , 대신를 사용 :

function getSortedKeys(obj) {
    var keys = []; for(var key in obj) keys.push(key);
    return keys.sort(function(a,b){return obj[b]-obj[a]});
}

당신은 (당신과 같은) 객체를 덤프하고 키 배열을 가져옵니다-eh 속성-다시, eh, 값, eh, 객체의 (숫자) 값에 따라 내림차순으로 정렬됩니다.

값이 숫자 인 경우에만 작동합니다. Tweek는 function(a,b)정렬 메커니즘을 변경하여 오름차순으로 작동하거나 string값에 대해 작동 합니다 (예 :). 독자를위한 연습 문제로 남았습니다.


1
이 완벽하게 작동하고 적은 코드를 다음 위의 답변입니다
jshill103

1
- 나는 대부분의 브라우저는 요즘 단지 Object.keys ()를 지원하는 점에 유의해야한다 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...을
commonpike

object.keys가 더 나은 이유는 무엇입니까?
john ktejik

1
@johnktejik이 답변은 2012 년부터였습니다 :-) Object.keys ()는 요즘 표준이며 더 짧고 빠를 것입니다.
commonpike

2
... : 나는 피곤했다, 내가이 삭제하자
마누

16

값을 기준으로 (연관) 배열을 정렬하는 방법에서 다루는 계속되는 토론 및 기타 솔루션 내 경우에 가장 좋은 해결책은 saml (아래 인용)입니다.

배열은 숫자 인덱스 만 가질 수 있습니다. 이것을 Object 또는 Array of Objects로 다시 작성해야합니다.

var status = new Array();
status.push({name: 'BOB', val: 10});
status.push({name: 'TOM', val: 3});
status.push({name: 'ROB', val: 22});
status.push({name: 'JON', val: 7});

status.push방법 이 마음에 들면 다음과 같이 정렬 할 수 있습니다.

status.sort(function(a,b) {
    return a.val - b.val;
});

우수한! 해야 할 일 및 이름에 대한 알파 정렬 : return a.name> b.name.
mpemburn

1
알파벳 정렬의 경우 문자열 값을 sort()다르게 처리 하므로 동일한 대소 문자를 비교하십시오 . 이 stackoverflow.com/questions/6712034/…를 찾을 때까지 한 시간 동안 나를 엉망으로 만들었습니다 . 예; a.name.toLowerCase() > b.name.toLowerCase()
Dylan Valade 2016

5

실제로 JavaScript에는 "연관 배열"과 같은 것이 없습니다. 당신이 가진 것은 단지 평범한 오래된 물건입니다. 물론 그들은 일종의 연관 배열처럼 작동하며 키는 사용할 수 있지만 키 순서에 대한 의미는 없습니다.

객체를 객체 배열 (키 / 값 쌍)로 바꾸고 정렬 할 수 있습니다.

function sortObj(object, sortFunc) {
  var rv = [];
  for (var k in object) {
    if (object.hasOwnProperty(k)) rv.push({key: k, value:  object[k]});
  }
  rv.sort(function(o1, o2) {
    return sortFunc(o1.key, o2.key);
  });
  return rv;
}

그런 다음 비교기 기능으로 호출합니다.


+1 당신이 나를 이겼습니다. 저는 매우 유사한 설명과 코드를 작성했습니다.
gonchuki 2011 년

4

튜플이 마음에 들지 않으면 벤 블랭크의 대답을 변형 한 것입니다.

이렇게하면 몇 개의 문자가 절약됩니다.

var keys = [];
for (var key in sortme) {
  keys.push(key);
}

keys.sort(function(k0, k1) {
  var a = sortme[k0];
  var b = sortme[k1];
  return a < b ? -1 : (a > b ? 1 : 0);
});

for (var i = 0; i < keys.length; ++i) {
  var key = keys[i];
  var value = sortme[key];
  // Do something with key and value.
}

4

불필요한 합병증이 필요하지 않습니다 ...

function sortMapByValue(map)
{
    var tupleArray = [];
    for (var key in map) tupleArray.push([key, map[key]]);
    tupleArray.sort(function (a, b) { return a[1] - b[1] });
    return tupleArray;
}

이것의 출력은 맵이 아니라 배열의 배열입니다
Daniel

var stuff = {"a":1 , "b":3 , "c":0 } sortMapByValue(stuff) [Array[2], Array[2], Array[2]]
Daniel

가장 깨끗한 것 같아요. 그냥 마지막에지도에 변환을 추가
다니엘

1

나는 $ .each of jquery를 사용하지만 for 루프로 만들 수 있습니다. 개선 사항은 다음과 같습니다.

        //.ArraySort(array)
        /* Sort an array
         */
        ArraySort = function(array, sortFunc){
              var tmp = [];
              var aSorted=[];
              var oSorted={};

              for (var k in array) {
                if (array.hasOwnProperty(k)) 
                    tmp.push({key: k, value:  array[k]});
              }

              tmp.sort(function(o1, o2) {
                    return sortFunc(o1.value, o2.value);
              });                     

              if(Object.prototype.toString.call(array) === '[object Array]'){
                  $.each(tmp, function(index, value){
                      aSorted.push(value.value);
                  });
                  return aSorted;                     
              }

              if(Object.prototype.toString.call(array) === '[object Object]'){
                  $.each(tmp, function(index, value){
                      oSorted[value.key]=value.value;
                  });                     
                  return oSorted;
              }               
     };

이제 할 수 있습니다

    console.log("ArraySort");
    var arr1 = [4,3,6,1,2,8,5,9,9];
    var arr2 = {'a':4, 'b':3, 'c':6, 'd':1, 'e':2, 'f':8, 'g':5, 'h':9};
    var arr3 = {a: 'green', b: 'brown', c: 'blue', d: 'red'};
    var result1 = ArraySort(arr1, function(a,b){return a-b});
    var result2 = ArraySort(arr2, function(a,b){return a-b});
    var result3 = ArraySort(arr3, function(a,b){return a>b});
    console.log(result1);
    console.log(result2);       
    console.log(result3);

1

여기에서 특정 사례에 대한 최선의 접근 방식은 제안 된 공통점 입니다. 현대 브라우저에서 작동하는 약간의 개선 사항은 다음과 같습니다.

// aao is the "associative array" you need to "sort"
Object.keys(aao).sort(function(a,b){return aao[b]-aao[a]});

이것은 쉽게 적용 할 수 있으며 특정 경우에 잘 작동하므로 다음을 수행 할 수 있습니다.

let aoo={};
aao["sub2"]=1;
aao["sub0"]=-1;
aao["sub1"]=0;
aao["sub3"]=1;
aao["sub4"]=0;

let sk=Object.keys(aao).sort(function(a,b){return aao[b]-aao[a]});

// now you can loop using the sorted keys in `sk` to do stuffs
for (let i=sk.length-1;i>=0;--i){
 // do something with sk[i] or aoo[sk[i]]
}

이 외에도 더 넓은 범위의 상황에서도 정렬하는 데 사용할 수있는보다 "일반적인"기능을 제공하며 방금 제안한 개선 사항과 Ben Blank (문자열 값 정렬) 및 PopeJohnPaulII ( 특정 개체 필드 / 속성별로 정렬) 오름차순 또는 하위 순서를 원하는지 결정할 수 있습니다.

// aao := is the "associative array" you need to "sort"
// comp := is the "field" you want to compare or "" if you have no "fields" and simply need to compare values
// intVal := must be false if you need comparing non-integer values
// desc := set to true will sort keys in descendant order (default sort order is ascendant)
function sortedKeys(aao,comp="",intVal=false,desc=false){
  let keys=Object.keys(aao);
  if (comp!="") {
    if (intVal) {
      if (desc) return keys.sort(function(a,b){return aao[b][comp]-aao[a][comp]});
      else return keys.sort(function(a,b){return aao[a][comp]-aao[a][comp]});
    } else {
      if (desc) return keys.sort(function(a,b){return aao[b][comp]<aao[a][comp]?1:aao[b][comp]>aao[a][comp]?-1:0});
      else return keys.sort(function(a,b){return aao[a][comp]<aao[b][comp]?1:aao[a][comp]>aao[b][comp]?-1:0});
    }
  } else {
    if (intVal) {
      if (desc) return keys.sort(function(a,b){return aao[b]-aao[a]});
      else return keys.sort(function(a,b){return aao[a]-aao[b]});
    } else {
      if (desc) return keys.sort(function(a,b){return aao[b]<aao[a]?1:aao[b]>aao[a]?-1:0});
      else return keys.sort(function(a,b){return aao[a]<aao[b]?1:aao[a]>aao[b]?-1:0});
    }
  }
}

다음 코드와 같은 것을 시도하여 기능을 테스트 할 수 있습니다.

let items={};
items['Edward']=21;
items['Sharpe']=37;
items['And']=45;
items['The']=-12;
items['Magnetic']=13;
items['Zeros']=37;
//equivalent to:
//let items={"Edward": 21, "Sharpe": 37, "And": 45, "The": -12, ...};

console.log("1: "+sortedKeys(items));
console.log("2: "+sortedKeys(items,"",false,true));
console.log("3: "+sortedKeys(items,"",true,false));
console.log("4: "+sortedKeys(items,"",true,true));
/* OUTPUT
1: And,Sharpe,Zeros,Edward,Magnetic,The
2: The,Magnetic,Edward,Sharpe,Zeros,And
3: The,Magnetic,Edward,Sharpe,Zeros,And
4: And,Sharpe,Zeros,Edward,Magnetic,The
*/

items={};
items['k1']={name:'Edward',value:21};
items['k2']={name:'Sharpe',value:37};
items['k3']={name:'And',value:45};
items['k4']={name:'The',value:-12};
items['k5']={name:'Magnetic',value:13};
items['k6']={name:'Zeros',value:37};

console.log("1: "+sortedKeys(items,"name"));
console.log("2: "+sortedKeys(items,"name",false,true));
/* OUTPUT
1: k6,k4,k2,k5,k1,k3
2: k3,k1,k5,k2,k4,k6
*/

이미 말했듯이 작업이 필요한 경우 정렬 된 키를 반복 할 수 있습니다.

let sk=sortedKeys(aoo);
// now you can loop using the sorted keys in `sk` to do stuffs
for (let i=sk.length-1;i>=0;--i){
 // do something with sk[i] or aoo[sk[i]]
}

마지막으로 Object.keysArray.sort에 대한 유용한 참조


0

그래서 그것은 거기에 있고 누군가는 튜플 기반 정렬을 찾고 있습니다. 이것은 배열의 객체의 첫 번째 요소를 두 번째 요소보다 비교합니다. 즉, 아래 예에서 먼저 "a"로 비교 한 다음 "b"로 비교합니다.

let arr = [
    {a:1, b:2, c:3},
    {a:3, b:5, c:1},
    {a:2, b:3, c:9},
    {a:2, b:5, c:9},
    {a:2, b:3, c:10}    
]

function getSortedScore(obj) {
    var keys = []; 
    for(var key in obj[0]) keys.push(key);
    return obj.sort(function(a,b){
        for (var i in keys) {
            let k = keys[i];
            if (a[k]-b[k] > 0) return -1;
            else if (a[k]-b[k] < 0) return 1;
            else continue;
        };
    });
}

console.log(getSortedScore(arr))

출력

 [ { a: 3, b: 5, c: 1 },
  { a: 2, b: 5, c: 9 },
  { a: 2, b: 3, c: 10 },
  { a: 2, b: 3, c: 9 },
  { a: 1, b: 2, c: 3 } ]

-4

@commonpike의 대답은 "올바른 사람"이지만 그가 계속해서 댓글을다는 동안 ...

요즘 대부분의 브라우저는 Object.keys()

그래 .. Object.keys()입니다 WAY 더 .

그러나 더 나은 것은 무엇 입니까? 야, 그게 다야 coffeescript!

sortedKeys = (x) -> Object.keys(x).sort (a,b) -> x[a] - x[b]

sortedKeys
  'a' :  1
  'b' :  3
  'c' :  4
  'd' : -1

[ 'd', 'a', 'b', 'c' ]

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.