web-dev-qa-db-fra.com

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 (par ordre décroissant) ses valeurs, où le résultat serait un tableau avec les indices respectifs dans cet ordre:

sub2, sub3, sub1, sub4, sub0?
77
John Smith

Javascript n'a pas les "matrices associatives" comme vous les envisagez. Au lieu de cela, vous avez simplement la possibilité de définir les propriétés d'un objet à l'aide d'une syntaxe semblable à un tableau (comme dans votre exemple), ainsi que la possibilité d'itérer sur les propriétés d'un objet.

Le résultat de cela est qu’il n’ya aucune garantie quant à l’ordre ordre dans lequel vous parcourez les propriétés, il n’ya donc rien de mieux qu’une sorte. Au lieu de cela, vous devrez convertir les propriétés de votre objet en un tableau "true" (qui garantit l'ordre). Voici un extrait de code permettant de convertir un objet en un tableau de deux tuples (tableaux de deux éléments), en le triant comme vous le décrivez, puis en le parcourant:

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 trouverez peut-être plus naturel de placer cela 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>

110
Ben Blank

Au lieu de vous corriger 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 videz un objet (comme le vôtre) et obtenez un tableau des clés - eh properties - back, triées par ordre décroissant selon la valeur (numérique) de, euh, les valeurs de, eh, objet.

Cela ne fonctionne que si vos valeurs sont numériques. Tweek la petite function(a,b) dedans pour changer le mécanisme de tri afin de travailler par ordre croissant, ou de travailler pour les valeurs string (par exemple). Gauche comme un exercice pour le lecteur.

EDIT: les gens continuent à voter pour cette réponse, mais elle est vraiment ancienne. S'il vous plaît réexaminez pourquoi vous n'utilisez pas simplement Object.keys () de nos jours: var keys = Object.keys(obj);

74
commonpike

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

Les tableaux ne peuvent avoir que des index numériques. Vous devrez réécrire ceci sous la forme d'un objet ou d'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
PopeJohnPaulII

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

Vous pouvez transformer votre objet en un tableau d'objets (paires clé/valeur) et trier ce qui suit:

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

Ensuite, vous appelez cela avec une fonction de comparaison.

5
Pointy

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
bop

Voici une variante de la réponse de ben blank, si vous n'aimez pas les n-uplets. 

Cela vous évite 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
donquixote

j'utilise $ .each of jquery mais vous pouvez le faire avec une boucle for, une amélioration est la suivante:

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

Alors maintenant tu peux 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
demosthenes

La meilleure approche pour le cas spécifique ici, à mon avis, est celle suggérée par commonpike. Une petite amélioration, je dirais que cela 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 fonctionner très bien dans le cas spécifique ici afin que vous puissiez 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 l'amélioration que je viens de suggérer aux approches des réponses par Ben Blank ) et PopeJohnPaulII (trier par champ/propriété d’objet spécifique) et vous permet de décider si vous voulez un ordre ascendant ou descendant, le voici:

// 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 faire une boucle sur les 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]]
}

Enfin et surtout, quelques références utiles à Object.keys et Array.sort

0
danicotra

Juste pour qu'il soit là-bas et que quelqu'un recherche des tris basés sur Tuple. Ceci comparera le premier élément de l'objet dans le tableau, le deuxième élément, etc. C'est-à-dire que dans l'exemple ci-dessous, il comparera d'abord par "a", ensuite 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))

SORTIES

 [ { 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
Shayan C