Javascript 如何通过Javascript中的值对关联数组进行排序?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5199901/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 16:08:32  来源:igfitidea点击:

How to sort an associative array by its values in Javascript?

javascriptarrayssortingassociative

提问by John Smith

I have the associative array:

我有关联数组:

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

What is the most elegant way to sort (descending) by its values where the result would be an array with the respective indices in this order:

按其值排序(降序)的最优雅方法是什么,结果将是一个按以下顺序具有相应索引的数组:

sub2, sub3, sub1, sub4, sub0

?

?

回答by Ben Blank

Javascript doesn't have "associative arrays" the way you're thinking of them. Instead, you simply have the ability to set object properties using array-like syntax (as in your example), plus the ability to iterate over an object's properties.

Javascript 没有您想象中的“关联数组”。相反,您只需能够使用类似数组的语法(如您的示例中所示)设置对象属性,以及迭代对象属性的能力。

The upshot of this is that there is no guarantee as to the orderin which you iterate over the properties, so there is nothing like a sort for them. Instead, you'll need to convert your object properties into a "true" array (which does guarantee order). Here's a code snippet for converting an object into an array of two-tuples (two-element arrays), sorting it as you describe, then iterating over it:

这样做的结果是无法保证您对属性进行迭代的顺序,因此对于它们来说没有什么比排序更好的了。相反,您需要将对象属性转换为“真实”数组(它可以保证顺序)。这是一个代码片段,用于将对象转换为二元组(双元素数组)数组,按照您的描述对其进行排序,然后对其进行迭代:

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
}

You may find it more natural to wrap this in a function which takes a callback:

您可能会发现将其包装在一个接受回调的函数中更自然:

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>

回答by commonpike

Instead of correcting you on the semantics of an 'associative array', I think this is what you want:

而不是纠正你的“关联数组”的语义,我认为这就是你想要的:

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

for really old browsers, use this instead:

对于非常旧的浏览器,请改用:

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

You dump in an object (like yours) and get an array of the keys - eh properties - back, sorted descending by the (numerical) value of the, eh, values of the, eh, object.

您转储到一个对象(如您的对象)中并获得一个键数组 - eh 属性 - 返回,按 eh 对象的(数值)值降序排序。

This only works if your values are numerical. Tweek the little function(a,b)in there to change the sorting mechanism to work ascending, or work for stringvalues (for example). Left as an exercise for the reader.

这仅在您的值是数字时才有效。Tweek the little function(a,b)in there 改变排序机制以升序工作,或为string值工作(例如)。留给读者作为练习。

回答by PopeJohnPaulII

Continued discussion & other solutions covered at How to sort an (associative) array by value?with the best solution (for my case) being by saml(quoted below).

继续讨论与其他解决方案覆盖在如何排序值(关联)数组?最好的解决方案(就我而言)是由saml 提供的(引用如下)。

Arrays can only have numeric indexes. You'd need to rewrite this as either an Object, or an 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});

If you like the status.pushmethod, you can sort it with:

如果您喜欢该status.push方法,可以使用以下方法对其进行排序:

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

回答by Pointy

There really isn't any such thing as an "associative array" in JavaScript. What you've got there is just a plain old object. They work kind-of like associative arrays, of course, and the keys are available but there's no semantics around the order of keys.

JavaScript 中确实没有“关联数组”这样的东西。你在那里得到的只是一个普通的旧物体。当然,它们的工作方式有点像关联数组,并且键可用,但键的顺序没有语义。

You could turn your object into an array of objects (key/value pairs) and sort that:

您可以将对象转换为对象数组(键/值对)并对其进行排序:

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

Then you'd call that with a comparator function.

然后你会用一个比较器函数调用它。

回答by donquixote

Here is a variation of ben blank's answer, if you don't like tuples.

如果您不喜欢元组,这里是 ben Blank 答案的变体。

This saves you a few characters.

这为您节省了几个字符。

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

回答by bop

No unnecessary complication required...

不需要不必要的并发症...

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

回答by demosthenes

i use $.each of jquery but you can make it with a for loop, an improvement is this:

我使用 $.each 的 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;
              }               
     };

So now you can do

所以现在你可以做

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

回答by danicotra

The best approach for the specific case here, in my opinion, is the one commonpikesuggested. A little improvement I'd suggest that works in modern browsers is:

在我看来,针对此处特定情况的最佳方法是建议的一种常用方法。我建议在现代浏览器中工作的一点改进是:

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

This could apply easily and work great in the specific case here so you can do:

这可以很容易地应用并且在此处的特定情况下效果很好,因此您可以执行以下操作:

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

Besides of this, I provide here a more "generic" function you can use to sort even in wider range of situations and that mixes the improvement I just suggested with the approaches of the answers by Ben Blank(sorting also string values) and PopeJohnPaulII(sorting by specific object field/property) and lets you decide if you want an ascendant or descendant order, here it is:

除此之外,我在这里提供了一个更“通用”的函数,您甚至可以在更广泛的情况下使用它进行排序,并且将我刚刚建议的改进与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});
    }
  }
}

You can test the functionalities trying something like the following code:

您可以尝试使用以下代码来测试功能:

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
*/

As I already said, you can loop over sorted keys if you need doing stuffs

正如我已经说过的,如果你需要做一些事情,你可以遍历排序的键

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

Last, but not least, some useful references to Object.keysand Array.sort

最后,但并非最不重要的是,对Object.keysArray.sort 的一些有用参考

回答by Shayan C

Just so it's out there and someone is looking for tuple based sorts. This will compare the first element of the object in array, than the second element and so on. i.e in the example below, it will compare first by "a", then by "b" and so on.

就这样它就在那里,有人正在寻找基于元组的排序。这将比较数组中对象的第一个元素,而不是第二个元素,依此类推。即在下面的示例中,它将首先比较“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))

OUPUTS

输出

 [ { 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 } ]

回答by Alex Gray

@commonpike's answer is "the right one", but as he goes on to comment...

@commonpike 的回答是“正确的”,但当他继续评论时......

most browsers nowadays just support Object.keys()

现在大多数浏览器只支持 Object.keys()

Yeah.. Object.keys()is WAY better.

是啊..Object.keys()更好的方式

But what's even better? Duh, it's it in coffeescript!

但还有什么更好的呢?呃,它进去了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' ]

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