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
?
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;
}
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()
.
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 )
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);
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.
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);
});
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>');
});
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!
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.
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'
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 !