Comment trier un tableau associatif par ses valeurs en Javascript?

j'ai le tableau associatif:

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

Quelle est la manière la plus élégante de trier (décroissant) par ses valeurs où le résultat serait un tableau avec les indices respectifs dans cet ordre:

sub2, sub3, sub1, sub4, sub0?
76
demandé sur Eric Leschinski 2011-03-05 01:17:52

10 réponses

Javascript n'a pas de" tableaux associatifs " comme vous le pensez. Au lieu de cela, vous avez simplement la possibilité de définir des propriétés de l'objet en utilisant une syntaxe de type tableau (comme dans votre exemple), plus la possibilité d'itérer sur les propriétés d'un objet.

La conséquence de cela est qu'il n'y a aucune garantie quant à la ordre où vous parcourez les propriétés, donc il n'y a rien comme une sorte pour eux. Au lieu de cela, vous aurez besoin de convertir votre propriétés de l'objet dans un tableau "true" (qui garantit l'ordre). Voici un extrait de code pour convertir un objet en un tableau de deux tuples (tableaux à deux éléments), en le triant comme vous le décrivez, puis en itérant dessus:

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
}

vous pouvez trouver plus naturel de l'envelopper dans une fonction qui prend un rappel:

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>
108
répondu Ben Blank 2017-08-04 05:30:16

au Lieu de corriger vous sur la sémantique d'un tableau associatif", je pense que c'est ce que vous voulez:

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

vous dump dans un objet (comme le vôtre) et obtenir un tableau des clés - propriétés eh - retour, trié Descendant Par la valeur (numérique) de, eh, les valeurs de, eh, l'objet.

Cela ne fonctionne que si vos valeurs sont numériques. Tweek le petit function(a,b) là-dedans pour changer le mécanisme de tri pour travailler ascendant, ou travailler pour les valeurs string (par exemple). Laissé comme exercice pour le lecteur.

EDIT: les gens continuent à upvoting cette réponse, mais il est vraiment vieux. Merci reconsidérez pourquoi vous n'utilisez pas seulement L'objet .keys () de nos jours: var keys = Object.keys(obj);

71
répondu commonpike 2018-08-31 09:57:57

la Poursuite de la discussion et d'autres solutions de couverts à Comment trier un (associatif) tableau par valeur? avec la meilleure solution (pour mon cas) étant de saml (cité ci-dessous).

Les tableaux

ne peuvent avoir que des index numériques. Vous devez réécrire ceci soit comme un objet, soit comme un tableau d'objets.

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

si vous aimez la méthode status.push , vous pouvez la Trier avec:

status.sort(function(a,b) {
    return a.val - b.val;
});
15
répondu PopeJohnPaulII 2017-05-23 11:55:04

il n'existe vraiment pas de" tableau associatif " en JavaScript. Ce que vous avez là n'est qu'un simple objet. Ils fonctionnent comme des tableaux associatifs, bien sûr, et les clés sont disponibles, mais il n'y a pas de sémantique autour de l'ordre des clés.

vous pouvez transformer votre objet en un tableau d'objets (paires clé / valeur) et trier que:

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

alors on appelle ça avec une fonction de comparaison.

5
répondu Pointy 2011-03-04 22:30:42

voici une variante de la réponse de ben blank, si vous n'aimez pas les tuples.

cela vous permet de sauvegarder quelques caractères.

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
répondu donquixote 2014-12-18 20:50:44

aucune complication inutile requise...

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;
}
4
répondu bop 2015-01-10 05:07:26

j'utilise $.chacun de jquery mais vous pouvez le faire avec une boucle for, une amélioration est ceci:

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

donc maintenant vous pouvez faire

    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
répondu demosthenes 2012-07-19 13:22:36

juste pour qu'il soit dehors et que quelqu'un cherche des sortes basées sur tuple. Ceci comparera le premier élément de l'objet dans array, que le deuxième élément et ainsi de suite. j'.e dans l'exemple ci-dessous, il compare d'abord par "a", puis par "b" et ainsi de suite.

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 } ]
0
répondu Shayan C 2017-06-27 10:45:34

la meilleure approche pour le cas particulier ici, à mon avis, est celle commonpike suggérée. Une petite amélioration je dirais que fonctionne dans les navigateurs modernes est:

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

cela pourrait s'appliquer facilement et travailler très bien dans le cas spécifique ici donc vous pouvez faire:

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

en plus de cela, je fournis ici une fonction plus "générique" que vous pouvez utiliser pour trier même dans un plus large éventail de situations et qui mélange les amélioration que je viens de suggérer avec les approches des réponses par Ben Blank (tri aussi des valeurs de chaîne de caractères) et PopeJohnPaulII (Tri par champ Objet/propriété spécifique) et vous permet de décider si vous voulez un ordre ascendant ou descendant, ici il est:

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

vous pouvez tester les fonctionnalités en essayant quelque chose comme le code suivant:

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

comme je l'ai déjà dit, Vous pouvez boucler clés triées si vous avez besoin de faire des choses

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

dernière, mais non des moindres, quelques références utiles à L'objet .touches et tableau.trier

0
répondu danicotra 2018-06-30 16:53:45

la réponse de @commonpike est "la bonne", mais comme il continue à commenter...

la plupart des navigateurs de nos jours il suffit de prendre en charge Object.keys()

Oui.. Object.keys() est beaucoup mieux .

mais qu'est-ce que encore mieux ? C'est dans 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' ]

-4
répondu Alex Gray 2015-11-03 03:00:42