Comment trier un tableau à 2 dimensions par valeur de colonne?


90

Quelqu'un peut-il m'aider à trier un tableau à 2 dimensions en JavaScript?

Il contiendra des données au format suivant:

[12, AAA]
[58, BBB]
[28, CCC]
[18, DDD]

Cela devrait ressembler à ceci une fois trié:

[12, AAA]
[18, DDD]
[28, CCC]
[58, BBB]

Donc, en gros, tri par la première colonne.

À votre santé


3
Voici tout ce que vous devez savoir: MDN - Array.sort ()
jahroy

1
Veuillez accepter la réponse de @PramodVemulapalli, tous ceux qui sont actuellement très votés ont tort!
Bergi

@jahroy: Il ne s'agit pas de la coercition de type, mais des exigences pour des fonctions de comparaison cohérentes.
Bergi

Réponses:


110

C'est aussi simple que ça:

var a = [[12, 'AAA'], [58, 'BBB'], [28, 'CCC'],[18, 'DDD']];

a.sort(sortFunction);

function sortFunction(a, b) {
    if (a[0] === b[0]) {
        return 0;
    }
    else {
        return (a[0] < b[0]) ? -1 : 1;
    }
}

Je vous invite à lire la documentation .

Si vous souhaitez trier par la deuxième colonne, vous pouvez le faire:

a.sort(compareSecondColumn);

function compareSecondColumn(a, b) {
    if (a[1] === b[1]) {
        return 0;
    }
    else {
        return (a[1] < b[1]) ? -1 : 1;
    }
}

4
Veuillez tester votre code. jsfiddle.net/DuR4B/2 . Directement à partir du lien de documentation que vous avez posté: "Si compareFunction n'est pas fourni, les éléments sont triés en les convertissant en chaînes et en comparant les chaînes dans l'ordre lexicographique (" dictionnaire "ou" annuaire téléphonique ", pas numérique). Par exemple," 80 "vient avant "9" dans l'ordre lexicographique, mais dans un tri numérique 9 vient avant 80. "
Ian

3
@Ian - Vous avez raison. Bon point. Je suppose que j'étais trop excité de prouver un point sur la simplicité. Je l'ai testé, mais pas complètement. Maintenant, je vais le réparer ... J'aurais aimé que les exemples de données aient prouvé votre point de vue avant de répandre cet œuf sur mon visage!
jahroy

Haha je sais que je sais, je déteste quand ce genre de chose arrive. Cela a l'air si juste mais quelque chose le change en interne qui ne fonctionne pas comme prévu. Un peu comme comparer des chaînes avec <ou> . Quoi qu'il en soit, j'aime la mise à jour :)
Ian

1
@Ash - Le meilleur endroit pour regarder est la documentation. J'aime la documentation de Mozilla, donc quand j'ai une question sur une fonction JS, je cherche toujours sur "mdn {{function_name}} " . Dans ce cas, le terme de recherche serait "mdn array.sort" qui vous amène ici .
jahroy

1
... comme vous le verrez dans la documentation, la méthode array.sort () prend une fonction comme argument, ce qui est assez courant en JavaScript. La méthode array.sort () est conçue de manière à savoir quoi faire de la fonction qui lui est passée: elle l'utilise pour comparer ses éléments. Voici un violon vraiment boiteux que j'ai fait pour essayer de montrer comment vous passez des fonctions comme références ... désolé, c'est si mauvais.
jahroy

65

La meilleure approche serait d'utiliser ce qui suit, car il peut y avoir des valeurs répétitives dans la première colonne.

var arr = [[12, 'AAA'], [12, 'BBB'], [12, 'CCC'],[28, 'DDD'], [18, 'CCC'],[12, 'DDD'],[18, 'CCC'],[28, 'DDD'],[28, 'DDD'],[58, 'BBB'],[68, 'BBB'],[78, 'BBB']];

arr.sort(function(a,b) {
    return a[0]-b[0]
});

C'est la bonne réponse, elle prend en compte les deux chiffres du numéro. Merci!
pseudo le

52

essaye ça

//WITH FIRST COLUMN
arr = arr.sort(function(a,b) {
    return a[0] - b[0];
});


//WITH SECOND COLUMN
arr = arr.sort(function(a,b) {
    return a[1] - b[1];
});

Remarque: La réponse d'origine a utilisé un supérieur à (>) au lieu d'un moins (-), ce que les commentaires qualifient d'incorrects.


8
8 votes positifs pour une solution totalement erronée? Je ne peux pas le croire. Veuillez lire les fonctions de comparaison et comprendre quand elles doivent renvoyer des valeurs négatives.
Bergi

6
Comme l'a déclaré Bergi, ce n'est pas la bonne solution. Bien que cela puisse fonctionner dans de nombreux cas, il y aura des moments où cela ne fonctionnera pas comme prévu et vous vous grattez la tête (cela m'est arrivé). Le nœud du problème est que la fonction de comparaison dans cette solution ne renvoie que deux états (vrai / 1, faux / 0), mais elle devrait renvoyer trois états (zéro, supérieur à zéro et inférieur à zéro).
thdoan

1
N'a pas travaillé pour moi. @jahroy est l'homme avec la bonne réponse
erdomester

Juste une note pour ceux qui liront les commentaires: La réponse a été corrigée le 5 janvier. Elle est correcte maintenant (la fonction de comparaison renvoie trois états possibles).
marlar

@Bergi, merci de l'avoir signalé. (pour moi, cela ne fonctionne pas correctement dans IE11) et je n'ai pas été en mesure de comprendre (pourquoi cela fonctionne dans chrome) avant d'avoir vu votre commentaire. Merci!
Alex Nevsky

12

Utilisation de la fonction flèche et tri selon le deuxième champ de chaîne

var a = [[12, 'CCC'], [58, 'AAA'], [57, 'DDD'], [28, 'CCC'],[18, 'BBB']];
a.sort((a, b) => a[1].localeCompare(b[1]));
console.log(a)


10

Si vous êtes comme moi, vous ne voudrez pas changer chaque index chaque fois que vous voulez changer la colonne par laquelle vous triez.

function sortByColumn(a, colIndex){

    a.sort(sortFunction);

    function sortFunction(a, b) {
        if (a[colIndex] === b[colIndex]) {
            return 0;
        }
        else {
            return (a[colIndex] < b[colIndex]) ? -1 : 1;
        }
    }

    return a;
}

var sorted_a = sortByColumn(a, 2);

Je viens de voir votre réponse, après avoir rédigé une réponse moi-même avec exactement le même raisonnement - avec une petite différence - je renvoie en fait la fonction pour trier directement.
olamotte

3

Rien de spécial, juste économiser le coût nécessaire pour renvoyer une valeur à un certain index à partir d'un tableau.

function sortByCol(arr, colIndex){
    arr.sort(sortFunction)
    function sortFunction(a, b) {
        a = a[colIndex]
        b = b[colIndex]
        return (a === b) ? 0 : (a < b) ? -1 : 1
    }
}
// Usage
var a = [[12, 'AAA'], [58, 'BBB'], [28, 'CCC'],[18, 'DDD']]
sortByCol(a, 0)
console.log(JSON.stringify(a))
// "[[12,"AAA"],[18,"DDD"],[28,"CCC"],[58,"BBB"]]"

En quoi cette réponse est-elle différente de la mienne ici ?
Charles Clayton

1
1. vous utilisez a[colIndex]encore et encore mais je l'attrape ici a = a[colIndex]. C'est plus efficace. 2. J'utilise une saveur différente de if, ce qui la rend plus courte. 3. Je ne retourne pas arrsuite à une sortByColfonction, ce qui signifie que ma fonction ne peut pas être utilisée pour créer une autre référence. J'espère que cela aide!
Vikas Gautam

3

en une seule ligne:

var cars = [
  {type:"Volvo", year:2016},
  {type:"Saab", year:2001},
  {type:"BMW", year:2010}
]


function myFunction() {
  return cars.sort((a, b)=> a.year - b.year)
}

3

Si vous souhaitez trier en fonction de la première colonne (qui contient une valeur numérique ), essayez ceci:

arr.sort(function(a,b){
  return a[0]-b[0]
})

Si vous souhaitez trier en fonction de la deuxième colonne (qui contient une valeur de chaîne ), essayez ceci:

arr.sort(function(a,b){
  return a[1].charCodeAt(0)-b[1].charCodeAt(0)
})

PS pour le deuxième cas, vous devez comparer leurs valeurs ASCII.

J'espère que cela t'aides.


0

Comme mon cas d'utilisation implique des dizaines de colonnes, j'ai un peu développé la réponse de @ jahroy. (également juste réalisé que @ charles-clayton avait la même idée.)
Je passe le paramètre par lequel je veux trier, et la fonction de tri est redéfinie avec l'index souhaité pour que la comparaison ait lieu.

var ID_COLUMN=0
var URL_COLUMN=1

findings.sort(compareByColumnIndex(URL_COLUMN))

function compareByColumnIndex(index) {
  return function(a,b){
    if (a[index] === b[index]) {
        return 0;
    }
    else {
        return (a[index] < b[index]) ? -1 : 1;
    }
  }
}

0

Debout sur les épaules de charles-clayton et @ vikas-gautam, j'ai ajouté le test de cordes qui est nécessaire si une colonne a des chaînes comme dans OP.

return isNaN(a-b) ? (a === b) ? 0 : (a < b) ? -1 : 1 : a-b  ;

Le test isNaN(a-b)détermine si les chaînes ne peuvent pas être converties en nombres. S'ils le peuvent, le a-btest est valide.

Notez que le tri d'une colonne de types mixtes donnera toujours un résultat divertissant car le test d'égalité stricte (a === b)retournera toujours false. Voir MDN ici

Ceci est le script complet avec le test Logger - à l'aide de Google Apps Script.

function testSort(){

function sortByCol(arr, colIndex){
    arr.sort(sortFunction);
    function sortFunction(a, b) {
        a = a[colIndex];
        b = b[colIndex];
       return isNaN(a-b) ? (a === b) ? 0 : (a < b) ? -1 : 1 : a-b  ;  // test if text string - ie cannot be coerced to numbers.
       // Note that sorting a column of mixed types will always give an entertaining result as the strict equality test will always return false
       // see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness

       }
}
// Usage
var a = [ [12,'12', 'AAA'],
          [12,'11', 'AAB'],
          [58,'120', 'CCC'],
          [28,'08', 'BBB'],
          [18,'80', 'DDD'],
        ]
    var arr1 = a.map(function (i){return i;}).sort();  // use map to ensure tests are not corrupted by a sort in-place.

    Logger.log("Original unsorted:\n     " + JSON.stringify(a));
    Logger.log("Vanilla sort:\n     " + JSON.stringify(arr1));
    sortByCol(a, 0);
    Logger.log("By col 0:\n     " + JSON.stringify(a));
    sortByCol(a, 1);
    Logger.log("By col 1:\n     " + JSON.stringify(a));
    sortByCol(a, 2);
    Logger.log("By col 2:\n     " + JSON.stringify(a));

/* vanilla sort returns " [
                            [12,"11","AAB"],
                            [12,"12","AAA"],
                            [18,"80","DDD"],
                            [28,"08","BBB"],
                            [58,"120","CCC"]
                          ]
   if col 0 then returns "[
                            [12,'12',"AAA"],
                            [12,'11', 'AAB'],
                            [18,'80',"DDD"],
                            [28,'08',"BBB"],
                            [58,'120',"CCC"]
                          ]"
   if col 1 then returns "[
                            [28,'08',"BBB"],
                            [12,'11', 'AAB'],
                            [12,'12',"AAA"],
                            [18,'80',"DDD"],
                            [58,'120',"CCC"],

                          ]"
   if col 2 then returns "[
                            [12,'12',"AAA"],
                            [12,'11', 'AAB'],
                            [28,'08',"BBB"],
                            [58,'120',"CCC"],
                            [18,'80',"DDD"],
                          ]"
*/

}

Mise à jour d'un intérêt éventuel - 2 juillet 2019. Le tri est désormais «stable». Lisez ici. (via Mathias BynensVerified @mathias) v8.dev/features/stable-sort
DeeKay789
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.