Comment trier un tableau sur plusieurs colonnes?

j'ai un tableau multidimensionnel. Le tableau primaire est un tableau de

[publicationID][publication_name][ownderID][owner_name] 

ce que j'essaie de faire est de trier le tableau par owner_name et ensuite par publication_name . Je sais que dans JavaScript vous avez Array.sort() , dans lequel vous pouvez mettre une fonction personnalisée, dans mon cas j'ai:

function mysortfunction(a, b) {
    var x = a[3].toLowerCase();
    var y = b[3].toLowerCase();

    return ((x < y) ? -1 : ((x > y) ? 1 : 0));
}

C'est très bien pour juste le tri sur une colonne, à savoir owner_name, mais comment puis-je le modifier pour trier sur owner_name , puis publication_name ?

85
demandé sur Alexander Abakumov 2010-05-07 00:27:04

11 réponses

si le nom du propriétaire diffère, Triez par eux. Sinon, utilisez le nom de publication pour tie breaker.

function mysortfunction(a, b) {

  var o1 = a[3].toLowerCase();
  var o2 = b[3].toLowerCase();

  var p1 = a[1].toLowerCase();
  var p2 = b[1].toLowerCase();

  if (o1 < o2) return -1;
  if (o1 > o2) return 1;
  if (p1 < p2) return -1;
  if (p1 > p2) return 1;
  return 0;
}
131
répondu dcp 2015-01-23 12:32:16

je pense que ce que vous cherchez est thenBy.js: https://github.com/Teun/thenBy.js

il vous permet d'utiliser le tableau standard.en quelque sorte, mais avec le style firstBy().thenBy().thenBy() .

Un exemple peut être vu ici .

46
répondu Teun D 2014-11-28 11:29:39

est tombé sur un besoin de faire SQL-style mélangé asc et desc tableau objet tries par des clés.

la solution de kennebec ci-dessus m'a aidé à obtenir ceci:

Array.prototype.keySort = function(keys) {

keys = keys || {};

// via
// /q/length-of-a-javascript-object-47147/"bob",  SCORE:2000, TIME:32,    AGE:16, COUNTRY:"US"},
  {USER:"jane", SCORE:4000, TIME:35,    AGE:16, COUNTRY:"DE"},
  {USER:"tim",  SCORE:1000, TIME:30,    AGE:17, COUNTRY:"UK"},
  {USER:"mary", SCORE:1500, TIME:31,    AGE:19, COUNTRY:"PL"},
  {USER:"joe",  SCORE:2500, TIME:33,    AGE:18, COUNTRY:"US"},
  {USER:"sally",    SCORE:2000, TIME:30,    AGE:16, COUNTRY:"CA"},
  {USER:"yuri", SCORE:3000, TIME:34,    AGE:19, COUNTRY:"RU"},
  {USER:"anita",    SCORE:2500, TIME:32,    AGE:17, COUNTRY:"LV"},
  {USER:"mark", SCORE:2000, TIME:30,    AGE:18, COUNTRY:"DE"},
  {USER:"amy",  SCORE:1500, TIME:29,    AGE:19, COUNTRY:"UK"}
];

var sorto = {
  SCORE:"desc",TIME:"asc", AGE:"asc"
};

obja.keySort(sorto);

donne le résultat suivant:

 0: {     USER: jane;     SCORE: 4000;    TIME: 35;       AGE: 16;    COUNTRY: DE;   }
 1: {     USER: yuri;     SCORE: 3000;    TIME: 34;       AGE: 19;    COUNTRY: RU;   }
 2: {     USER: anita;    SCORE: 2500;    TIME: 32;       AGE: 17;    COUNTRY: LV;   }
 3: {     USER: joe;      SCORE: 2500;    TIME: 33;       AGE: 18;    COUNTRY: US;   }
 4: {     USER: sally;    SCORE: 2000;    TIME: 30;       AGE: 16;    COUNTRY: CA;   }
 5: {     USER: mark;     SCORE: 2000;    TIME: 30;       AGE: 18;    COUNTRY: DE;   }
 6: {     USER: bob;      SCORE: 2000;    TIME: 32;       AGE: 16;    COUNTRY: US;   }
 7: {     USER: amy;      SCORE: 1500;    TIME: 29;       AGE: 19;    COUNTRY: UK;   }
 8: {     USER: mary;     SCORE: 1500;    TIME: 31;       AGE: 19;    COUNTRY: PL;   }
 9: {     USER: tim;      SCORE: 1000;    TIME: 30;       AGE: 17;    COUNTRY: UK;   }
 keySort: {  }

(utilisant une fonction d'impression de ici )

voici un exemple de jsbin .

edit: nettoyé et publié comme mksort.js sur github .

21
répondu bitless 2017-05-23 12:03:02

c'est pratique pour les alpha de toutes tailles. Passez-lui les index que vous voulez trier, dans l'ordre, comme arguments.

Array.prototype.deepSortAlpha= function(){
    var itm, L=arguments.length, order=arguments;

    var alphaSort= function(a, b){
        a= a.toLowerCase();
        b= b.toLowerCase();
        if(a== b) return 0;
        return a> b? 1:-1;
    }
    if(!L) return this.sort(alphaSort);

    this.sort(function(a, b){
        var tem= 0,  indx=0;
        while(tem==0 && indx<L){
            itm=order[indx];
            tem= alphaSort(a[itm], b[itm]); 
            indx+=1;        
        }
        return tem;
    });
    return this;
}

var arr= [[ "Nilesh","Karmshil"], ["Pranjal","Deka"], ["Susants","Ghosh"],
["Shiv","Shankar"], ["Javid","Ghosh"], ["Shaher","Banu"], ["Javid","Rashid"]];

arr.deepSortAlpha(1,0);
16
répondu kennebec 2013-05-26 13:37:09

une bonne façon de trier sur de nombreux champs qui sont des chaînes est d'utiliser toLocaleCompare et l'opérateur booléen || .

quelque chose comme:

// Sorting record releases by name and then by title.
releases.sort((oldRelease, newRelease) => {
  const compareName = oldRelease.name.localeCompare(newRelease.name);
  const compareTitle = oldRelease.title.localeCompare(newRelease.title);

  return compareName || compareTitle;
})

si vous voulez trier sur plus de champs, vous pouvez simplement les enchaîner hors de la déclaration de retour avec plus d'opérateurs booléens.

10
répondu tbranyen 2016-09-30 20:58:45

vous pouvez concatter les 2 variables ensemble dans une clé USB et utiliser cela pour votre comparaison.

list.sort(function(a,b){
   var aCat = a.var1 + a.var2;
   var bCat = b.var1 + b.var2;
   return (aCat > bCat ? 1 : aCat < bCat ? -1 : 0);
});
7
répondu Tmac 2014-04-07 15:02:02

je suggère d'utiliser un compareur intégré et la chaîne l'ordre de tri voulu avec logique ou || .

function customSort(a, b) {
    return a[3].localeCompare(b[3]) || a[1].localeCompare(b[1]);
}

exemple pratique:

var array = [
    [0, 'Aluminium', 0, 'Francis'],
    [1, 'Argon', 1, 'Ada'],
    [2, 'Brom', 2, 'John'],
    [3, 'Cadmium', 3, 'Marie'],
    [4, 'Fluor', 3, 'Marie'],
    [5, 'Gold', 1, 'Ada'],
    [6, 'Kupfer', 4, 'Ines'],
    [7, 'Krypton', 4, 'Joe'],
    [8, 'Sauerstoff', 3, 'Marie'],
    [9, 'Zink', 5, 'Max']
];

array.sort(function (a, b) {
    return a[3].localeCompare(b[3]) || a[1].localeCompare(b[1]);
});

document.write('<pre>');
array.forEach(function (a) {
    document.write(JSON.stringify(a) + '<br>');
});
6
répondu Nina Scholz 2015-12-01 14:19:42

je travaillais avec ng-grid et j'avais besoin de trier plusieurs colonnes sur un tableau d'enregistrements retournés à partir d'une API, alors j'ai inventé cette fonction dynamique de tri multiple.

tout D'abord, ng-grid lance un "événement" pour "ngGridSorted" et passe cette structure en arrière, décrivant le sort:

sortData = {
    columns:    DOM Element,
    directions: [], //Array of string values desc or asc. Each index relating to the same index of fields
    fields:     [], //Array of string values
};

donc j'ai construit une fonction qui va générer dynamiquement une fonction de tri basée sur le sortData comme montré ci-dessus ( N'ayez pas peur de la barre de défilement! Il n'est que d'environ 50 lignes de long! Aussi, je suis désolé pour la descente. Il a empêché un scrollbar horizontal! ):

function SortingFunction(sortData)
{
    this.sortData = sortData;

    this.sort = function(a, b)
    {
        var retval = 0;

        if(this.sortData.fields.length)
        {
            var i = 0;

            /*
                Determine if there is a column that both entities (a and b)
                have that are not exactly equal. The first one that we find
                will be the column we sort on. If a valid column is not
                located, then we will return 0 (equal).
            */
            while(  (   !a.hasOwnProperty(this.sortData.fields[i]) 
                    ||  !b.hasOwnProperty(this.sortData.fields[i]) 
                    ||  (a.hasOwnProperty(this.sortData.fields[i]) 
                        && b.hasOwnProperty(this.sortData.fields[i]) 
                        && a[this.sortData.fields[i]] === b[this.sortData.fields[i]])
                    ) && i < this.sortData.fields.length){
                i++;
            }

            if(i < this.sortData.fields.length)
            {
                /*
                    A valid column was located for both entities
                    in the SortData. Now perform the sort.
                */
                if(this.sortData.directions 
                && i < this.sortData.directions.length 
                && this.sortData.directions[i] === 'desc')
                {
                    if(a[this.sortData.fields[i]] > b[this.sortData.fields[i]])
                        retval = -1;
                    else if(a[this.sortData.fields[i]] < b[this.sortData.fields[i]])
                        retval = 1;
                }
                else
                {
                    if(a[this.sortData.fields[i]] < b[this.sortData.fields[i]])
                        retval = -1;
                    else if(a[this.sortData.fields[i]] > b[this.sortData.fields[i]])
                        retval = 1;
                }
            }
        }

        return retval;
    }.bind(this);
}

je trie alors les résultats de mon API ( results ) comme suit:

results.sort(new SortingFunction(sortData).sort);

j'espère que quelqu'un d'autre apprécie cette solution autant que moi! Merci!

1
répondu WebWanderer 2016-01-12 17:33:34

j'ai trouvé multisotr . C'est simple, puissante et petite bibliothèque pour le tri multiple. J'ai eu besoin de trier un tableau d'objets avec des critères de tri dynamique:

const criteria = ['name', 'speciality']
const data = [
  { name: 'Mike', speciality: 'JS', age: 22 },
  { name: 'Tom', speciality: 'Java', age: 30 },
  { name: 'Mike', speciality: 'PHP', age: 40 },
  { name: 'Abby', speciality: 'Design', age: 20 },
]

const sorted = multisort(data, criteria)

console.log(sorted)
<script src="https://cdn.rawgit.com/peterkhayes/multisort/master/multisort.js"></script>

cette bibliothèque plus mutch puissante, c'était mon cas. Essayer.

1
répondu MiF 2018-04-18 12:45:18
function multiSort() {

    var args =$.makeArray( arguments ),
        sortOrder=1, prop='', aa='',  b='';

    return function (a, b) {

       for (var i=0; i<args.length; i++){

         if(args[i][0]==='-'){
            prop=args[i].substr(1)
            sortOrder=-1
         }
         else{sortOrder=1; prop=args[i]}

         aa = a[prop].toLowerCase()
         bb = b[prop].toLowerCase()

         if (aa < bb) return -1 * sortOrder;
         if (aa > bb) return 1 * sortOrder;

       }

       return 0
    }

}
empArray.sort(multiSort( 'lastname','firstname')) Reverse with '-lastname'
0
répondu Lewiss 2015-01-23 08:16:54

j'ai eu un problème similaire en affichant des blocs de mémoire à partir de la sortie d'une composition virtuelle de fonctions DOM. Fondamentalement, j'ai fait face au même problème que le tri de données multi-critères comme la notation des résultats des joueurs à travers le monde.

j'ai remarqué que le tri multi-critères est:

- sort by the first column
- if equal, sort by the second
- if equal, sort by the third
-  etc... nesting and nesting if-else

et si vous vous en fichez, vous pourriez échouer rapidement dans un enfer de nidification SI-AUTREMENT... comme des promesses de rappel...

Qu'en est-il si nous écrivons une fonction" prédicate " pour décider si quelle partie d'alternative utiliser ? Le prédicat est tout simplement:

// useful for chaining test
const decide = (test, other) => test === 0 ? other : test

maintenant après avoir écrit vos tests de classification (byCountrySize, byAge, byGameType, byScore, byLevel...) peu importe qui a besoin, vous pouvez pondérer vos tests( 1 = asc, -1 = desc, 0 = disable), les mettre dans un tableau, et appliquer une fonction de réduction 'decide' comme ceci:

const multisort = (s1, s2) => {
  const bcs = -1 * byCountrySize(s1, s2) // -1 = desc 
  const ba =  1 *byAge(s1, s2)
  const bgt = 0 * byGameType(s1, s2) // 0 = doesn't matter
  const bs = 1 * byScore(s1, s2)
  const bl = -1 * byLevel(s1, s2) // -1 = desc

  // ... other weights and criterias

  // array order matters !
  return [bcs, ba, bgt, bs, bl].reduce((acc, val) => decide(val, acc), 0)
}

// invoke [].sort with custom sort...
scores.sort(multisort)

et voilà ! C'est à vous pouvez définir vos propres critères / poids / commandes... mais vous obtenez l'idée. Espérons que cette aide !

EDIT: * s'assurer qu'il y a un ordre de tri total sur chaque colonne * être conscient de ne pas avoir de dépendances entre les ordres de colonnes, et aucune dépendance circulaire

si, non, le tri peut être instable !

0
répondu Hefeust 2018-09-06 22:17:31