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

时间:2021-08-27 15:13:58

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?

9 个解决方案

#1


105  

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 order in 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:

这样做的结果是,不能保证遍历属性的顺序,因此没有任何东西能像排序那样。相反,您需要将您的对象属性转换成一个“true”数组(它确实保证了顺序)。这里有一个代码片段,用于将对象转换成两个元组数组(两个元素数组),按您描述的方式进行排序,然后遍历它:

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>

#2


68  

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

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

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属性——返回,按对象的值(数值)降序排序。

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 string values (for example). Left as an exercise for the reader.

只有当你的值是数值时,这个才有效。Tweek在那里的小函数(a,b)改变排序机制以提升工作,或者为字符串值工作(例如)。留给读者作为练习。

EDIT: people keep upvoting this answer, but it's really old. Please reconsider why you're not just using Object.keys() nowadays.

编辑:人们一直在投票支持这个答案,但它真的太老了。请重新考虑为什么您现在不只是使用Object.keys()。

#3


15  

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.push method, you can sort it with:

如果你喜欢这个状态。push method,你可以用:

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

#4


5  

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.

然后用比较器函数调用它。

#5


4  

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

#6


4  

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

#7


1  

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

我用美元。每个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);

#8


0  

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

#9


-4  

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

是的. .种()是更好的方式。

But what's even better? Duh, it's it in 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']

#1


105  

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 order in 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:

这样做的结果是,不能保证遍历属性的顺序,因此没有任何东西能像排序那样。相反,您需要将您的对象属性转换成一个“true”数组(它确实保证了顺序)。这里有一个代码片段,用于将对象转换成两个元组数组(两个元素数组),按您描述的方式进行排序,然后遍历它:

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>

#2


68  

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

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

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属性——返回,按对象的值(数值)降序排序。

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 string values (for example). Left as an exercise for the reader.

只有当你的值是数值时,这个才有效。Tweek在那里的小函数(a,b)改变排序机制以提升工作,或者为字符串值工作(例如)。留给读者作为练习。

EDIT: people keep upvoting this answer, but it's really old. Please reconsider why you're not just using Object.keys() nowadays.

编辑:人们一直在投票支持这个答案,但它真的太老了。请重新考虑为什么您现在不只是使用Object.keys()。

#3


15  

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.push method, you can sort it with:

如果你喜欢这个状态。push method,你可以用:

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

#4


5  

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.

然后用比较器函数调用它。

#5


4  

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

#6


4  

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

#7


1  

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

我用美元。每个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);

#8


0  

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

#9


-4  

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

是的. .种()是更好的方式。

But what's even better? Duh, it's it in 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']