85 votes

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 (de manière descendante) par ses valeurs, le résultat étant un tableau avec les indices respectifs dans cet ordre :

sub2, sub3, sub1, sub4, sub0

1 votes

Puisque les propriétés des objets n'ont pas d'ordre défini par le langage, vous ne pouvez pas le faire (sauf, peut-être, dans certains moteurs JS en fonction de la manière particulière dont ils implémentent les propriétés).

116voto

Ben Blank Points 21786

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

Il en résulte qu'il n'y a aucune garantie quant à l'efficacité de l'opération. commander dans lequel vous itérez sur les propriétés, donc il n'y a rien comme un tri pour eux. À la place, vous devrez convertir les propriétés de votre objet en un "vrai" tableau (qui garantit l'ordre). Voici un extrait de code permettant de convertir un objet en un tableau de deux tuples (tableaux à deux éléments), de le trier comme vous le décrivez, puis d'itérer sur celui-ci :

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 d'envelopper cela dans une fonction qui prend un 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>

1 votes

La fonction tuples.sort peut être nettoyée en tuples.sort(function(a, b) { return a[1] - b[1] ; }) ;

2 votes

@stot - Si vos valeurs sont toutes des chiffres (comme dans l'exemple de l'auteur de la question), c'est tout à fait possible. Il semble que j'ai fourni par inadvertance une fonction de comparaison qui fonctionne également avec les chaînes de caractères :-)

0 votes

@Ben : oui vous avez raison, la version fournie est plus générale ;-)

86voto

commonpike Points 1779

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 = Object.keys(obj);
    return keys.sort(function(a,b){return obj[b]-obj[a]});
}

pour des navigateurs très anciens utilisez plutôt ceci :

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 saisissez un objet (comme le vôtre) et obtenez un tableau des clés - eh propriétés - en retour, trié par ordre décroissant de la valeur (numérique) des, eh, valeurs de l'objet.

Cela ne fonctionne que si vos valeurs sont numériques. Ajustez le petit function(a,b) pour changer le mécanisme de tri pour qu'il fonctionne de manière ascendante, ou pour qu'il fonctionne pour string valeurs (par exemple). Laissé comme un exercice pour le lecteur.

1 votes

Je dois noter que la plupart des navigateurs actuels ne prennent en charge que Object.keys(). developer.mozilla.org/fr/US/docs/Web/JavaScript/Référence/

0 votes

Pourquoi object.keys est-il meilleur ?

1 votes

@johnktejik cette réponse date de 2012 :-) Object.keys() est un standard de nos jours, et il est plus court et probablement plus rapide.

17voto

PopeJohnPaulII Points 147

Suite de la discussion et autres solutions couvertes à 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 devez réécrire ceci comme un objet ou 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 le status.push vous pouvez le trier avec :

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

0 votes

Excellent ! Pour faire un tri alpha sur le nom : return a.name > b.name.

1 votes

Pour le tri alphabétique, comparez les valeurs des chaînes de caractères dans le même cas car sort() les traite différemment. Ça m'a perturbé pendant une heure jusqu'à ce que je trouve ça. stackoverflow.com/questions/6712034/ Exemple ; a.name.toLowerCase() > b.name.toLowerCase()

5voto

Pointy Points 172438

Il n'existe pas vraiment de "tableau associatif" en JavaScript. Ce que vous avez là est simplement un vieil objet. Ils fonctionnent un peu 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 pourriez transformer votre objet en un tableau d'objets (paires clé/valeur) et le trier :

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

Vous l'appelez alors avec une fonction de comparaison.

0 votes

+1 vous m'avez battu à ce sujet. J'étais en train d'écrire une explication et un morceau de code très similaires.

4voto

donquixote Points 555

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

Cela vous permet d'économiser 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.
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X