278 votes

Javascript - trier un tableau en fonction d'un autre tableau

Est-il possible de trier et de réorganiser un tableau qui ressemble à ceci :

itemsArray = [ 
    ['Anne', 'a'],
    ['Bob', 'b'],
    ['Henry', 'b'],
    ['Andrew', 'd'],
    ['Jason', 'c'],
    ['Thomas', 'b']
]

pour qu'il corresponde à la disposition de ce tableau :

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

Malheureusement, je n'ai pas d'identifiant pour suivre l'évolution de la situation. Il faudrait que je donne la priorité au tableau des éléments pour qu'il corresponde le plus possible au tableau de tri.

Mise à jour :

Voici le résultat que je recherche :

itemsArray = [    
    ['Bob', 'b'],
    ['Jason', 'c'],
    ['Henry', 'b'],
    ['Thomas', 'b']
    ['Anne', 'a'],
    ['Andrew', 'd'],
]

Une idée sur la manière de procéder ?

456voto

Durgpal Singh Points 81

Réponse en une ligne.

itemsArray.sort(function(a, b){  
  return sortingArr.indexOf(a) - sortingArr.indexOf(b);
});

Ou même plus court :

itemsArray.sort((a, b) => sortingArr.indexOf(a) - sortingArr.indexOf(b));

95voto

georg Points 52691

Quelque chose comme :

items = [ 
    ['Anne', 'a'],
    ['Bob', 'b'],
    ['Henry', 'b'],
    ['Andrew', 'd'],
    ['Jason', 'c'],
    ['Thomas', 'b']
]

sorting = [ 'b', 'c', 'b', 'b', 'c', 'd' ];
result = []

sorting.forEach(function(key) {
    var found = false;
    items = items.filter(function(item) {
        if(!found && item[1] == key) {
            result.push(item);
            found = true;
            return false;
        } else 
            return true;
    })
})

result.forEach(function(item) {
    document.writeln(item[0]) /// Bob Jason Henry Thomas Andrew
})

Voici un code plus court, mais qui détruit la fonction sorting de la gamme :

result = items.map(function(item) {
    var n = sorting.indexOf(item[1]);
    sorting[n] = '';
    return [n, item]
}).sort().map(function(j) { return j[1] })

47voto

David Lewis Points 772

Si vous utilisez la fonction native de tri de tableau, vous pouvez passer un comparateur personnalisé à utiliser lors du tri du tableau. Le comparateur doit renvoyer un nombre négatif si la première valeur est inférieure à la seconde, zéro si elles sont égales, et un nombre positif si la première valeur est supérieure.

Donc, si je comprends bien l'exemple que vous donnez, vous pourriez faire quelque chose comme.. :

function sortFunc(a, b) {
  var sortingArr = [ 'b', 'c', 'b', 'b', 'c', 'd' ];
  return sortingArr.indexOf(a[1]) - sortingArr.indexOf(b[1]);
}

itemsArray.sort(sortFunc);

32voto

Don McCurdy Points 323

Cas 1 : Question originale (pas de bibliothèques)

Il y a beaucoup d'autres réponses qui fonctionnent :)

Cas 2 : Question originale (Lodash.js ou Underscore.js)

var groups = _.groupBy(itemArray, 1);
var result = _.map(sortArray, function (i) { return groups[i].shift(); });

Cas 3 : Trier le tableau 1 comme s'il s'agissait du tableau 2

Je suppose que la plupart des gens sont venus ici pour chercher un équivalent à array_multisort de PHP (c'est mon cas) et j'ai donc pensé poster cette réponse également. Il y a plusieurs options :

1. Il existe un Implémentation JS de array_multisort() . Merci à @Adnan de l'avoir signalé dans les commentaires. C'est quand même assez gros.

2. Rédigez votre propre texte. ( Démonstration de JSFiddle )

function refSort (targetData, refData) {
  // Create an array of indices [0, 1, 2, ...N].
  var indices = Object.keys(refData);

  // Sort array of indices according to the reference data.
  indices.sort(function(indexA, indexB) {
    if (refData[indexA] < refData[indexB]) {
      return -1;
    } else if (refData[indexA] > refData[indexB]) {
      return 1;
    }
    return 0;
  });

  // Map array of indices to corresponding values of the target array.
  return indices.map(function(index) {
    return targetData[index];
  });
}

3. Lodash.js o Underscore.js (deux bibliothèques populaires, plus petites et axées sur les performances) proposent des fonctions d'aide qui vous permettent de le faire :

    var result = _.chain(sortArray)
      .pairs()
      .sortBy(1)
      .map(function (i) { return itemArray[i[0]]; })
      .value();

...Ce qui (1) regroupera le sortArray en [index, value] (2) les trier par valeur (vous pouvez également fournir un callback ici), (3) remplacer chacune des paires par l'élément du tableau itemArray à l'index d'où provient la paire.

23voto

Sushruth Points 424

Il est probablement trop tard, mais vous pouvez également utiliser une version modifiée du code ci-dessous dans le style ES6. Ce code s'applique aux tableaux tels que :

var arrayToBeSorted = [1,2,3,4,5];
var arrayWithReferenceOrder = [3,5,8,9];

Le fonctionnement actuel :

arrayToBeSorted = arrayWithReferenceOrder.filter(v => arrayToBeSorted.includes(v));

L'opération réelle dans ES5 :

arrayToBeSorted = arrayWithReferenceOrder.filter(function(v) {
    return arrayToBeSorted.includes(v);
});

Devrait se traduire par arrayToBeSorted = [3,5]

Ne détruit pas le tableau de référence.

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