Javascript trie le tableau par deux champs


88
grouperArray.sort(function (a, b) {
    var aSize = a.gsize;
    var bSize = b.gsize;
    var aLow = a.glow;
    var bLow = b.glow;
    console.log(aLow + " | " + bLow);      
    return (aSize < bSize) ? -1 : (aSize > bSize) ? 1 : 0;
});

Ainsi, le code ci-dessus trie le tableau par gsize - du plus petit au plus grand. Ça marche bien. Mais si le gsize est le même, je voudrais qu'il trie ensuite par lueur.

Merci.


La fonction de tri réagit sur un résultat positif, négatif ou nul. vous pouvez donc simplement écrire: "return aSize - bSize". ce sera un code plus simple et plus lisible.

Réponses:


107
grouperArray.sort(function (a, b) {
    var aSize = a.gsize;
    var bSize = b.gsize;
    var aLow = a.glow;
    var bLow = b.glow;
    console.log(aLow + " | " + bLow);

    if(aSize == bSize)
    {
        return (aLow < bLow) ? -1 : (aLow > bLow) ? 1 : 0;
    }
    else
    {
        return (aSize < bSize) ? -1 : 1;
    }
});

170
grouperArray.sort(function (a, b) {   
    return a.gsize - b.gsize || a.glow - b.glow;
});

version plus courte


super raccourci! m'a aidé à mettre en place une solution plus complexe .. stackoverflow.com/questions/6101475/…
Joseph Poirier

3
Agréable et propre! La seule chose que cela ne fonctionne que pour les nombres.
Afanasii Kurakin

Pouvez-vous expliquer la logique ici?!. Cela a fonctionné pour moi sort an array with a key's value firstet puissort the result with another key's value
KTM

1
@KTM La logique est la suivante: si les deux gsize sont égaux, alors la première partie de la condition est égale à 0, ce qui est considéré comme faux, et la seconde partie de la condition est exécutée.
Scalpweb

@Scalpweb Ouais :) donc cela fonctionne pour trier un tableau avec n'importe quel nombre de clés une par une, non?! Belle astuce
KTM


14

Je me rends compte que cela a été demandé il y a quelque temps, mais j'ai pensé ajouter ma solution.

Cette fonction génère des méthodes de tri dynamiquement. fournissez simplement chaque nom de propriété enfant triable, précédé de +/- pour indiquer l'ordre croissant ou décroissant. Super réutilisable, et il n'a pas besoin de savoir quoi que ce soit sur la structure de données que vous avez créée. Cela pourrait être une preuve idiote - mais cela ne semble pas nécessaire.

function getSortMethod(){
    var _args = Array.prototype.slice.call(arguments);
    return function(a, b){
        for(var x in _args){
            var ax = a[_args[x].substring(1)];
            var bx = b[_args[x].substring(1)];
            var cx;

            ax = typeof ax == "string" ? ax.toLowerCase() : ax / 1;
            bx = typeof bx == "string" ? bx.toLowerCase() : bx / 1;

            if(_args[x].substring(0,1) == "-"){cx = ax; ax = bx; bx = cx;}
            if(ax != bx){return ax < bx ? -1 : 1;}
        }
    }
}

exemple d'utilisation:

items.sort (getSortMethod ('- prix', '+ priorité', '+ nom'));

ce serait le tri le itemsplus bas en pricepremier, les liens allant à l'élément avec le plus hautpriority . d'autres liens sont rompus par l'articlename

où items est un tableau comme:

var items = [
    { name: "z - test item", price: "99.99", priority: 0, reviews: 309, rating: 2 },
    { name: "z - test item", price: "1.99", priority: 0, reviews: 11, rating: 0.5 },
    { name: "y - test item", price: "99.99", priority: 1, reviews: 99, rating: 1 },
    { name: "y - test item", price: "0", priority: 1, reviews: 394, rating: 3.5 },
    { name: "x - test item", price: "0", priority: 2, reviews: 249, rating: 0.5 } ...
];

démo en direct: http://gregtaff.com/misc/multi_field_sort/

EDIT: Correction d'un problème avec Chrome.


C'est brillant
Azure

Réponse de génie!
Marius

pour dactylographié (pour ne pas obtenir un error TS2554: Expected 0 arguments, but got ..), utilisez la syntaxe ici: stackoverflow.com/a/4116634/5287221
Chananel P

6

Je suppose que l' opérateur ternaire((aSize < bSize) ? -1 : (aSize > bSize) ? 1 : 0;) vous a confus. Vous devriez consulter le lien pour mieux le comprendre.

Jusque-là, voici votre code explosé si / else.

grouperArray.sort(function (a, b) {
    if (a.gsize < b.gsize)
    {
        return -1;
    }
    else if (a.gsize > b.gsize)
    {
        return 1;
    }
    else
    {
        if (a.glow < b.glow)
        {
            return -1;
        }
        else if (a.glow > b.glow)
        {
            return 1;
        }
        return 0;
    }
});

6

Voici une implémentation pour ceux qui veulent quelque chose de plus générique qui fonctionnerait avec n'importe quel nombre de champs.

Array.prototype.sortBy = function (propertyName, sortDirection) {

    var sortArguments = arguments;
    this.sort(function (objA, objB) {

        var result = 0;
        for (var argIndex = 0; argIndex < sortArguments.length && result === 0; argIndex += 2) {

            var propertyName = sortArguments[argIndex];
            result = (objA[propertyName] < objB[propertyName]) ? -1 : (objA[propertyName] > objB[propertyName]) ? 1 : 0;

            //Reverse if sort order is false (DESC)
            result *= !sortArguments[argIndex + 1] ? 1 : -1;
        }
        return result;
    });

}

Fondamentalement, vous pouvez spécifier n'importe quel nombre de nom de propriété / sens de tri:

var arr = [{
  LastName: "Doe",
  FirstName: "John",
  Age: 28
}, {
  LastName: "Doe",
  FirstName: "Jane",
  Age: 28
}, {
  LastName: "Foo",
  FirstName: "John",
  Age: 30
}];

arr.sortBy("LastName", true, "FirstName", true, "Age", false);
//Will return Jane Doe / John Doe / John Foo

arr.sortBy("Age", false, "LastName", true, "FirstName", false);
//Will return John Foo / John Doe / Jane Doe

3
grouperArray.sort(function (a, b) {
  var aSize = a.gsize;
  var bSize = b.gsize;
  var aLow = a.glow;
  var bLow = b.glow;
  console.log(aLow + " | " + bLow);      
  return (aSize < bSize) ? -1 : (aSize > bSize) ? 1 : ( (aLow < bLow ) ? -1 : (aLow > bLow ) ? 1 : 0 );
});

3
grouperArray.sort(function (a, b) {
     var aSize = a.gsize;     
     var bSize = b.gsize;     
     var aLow = a.glow;
     var bLow = b.glow;
     console.log(aLow + " | " + bLow);
     return (aSize < bSize) ? -1 : (aSize > bSize) ? 1 : (aLow < bLow) ? -1 : (aLow > bLow) ? 1 : 0); }); 

3

Voici une implémentation qui utilise la récursivité pour trier selon n'importe quel nombre de champs de tri de 1 à infini. Vous lui transmettez un tableau de résultats qui est un tableau d'objets de résultat à trier et un tableau de tris qui est un tableau d'objets de tri définissant le tri. Chaque objet de tri doit avoir une clé "sélection" pour le nom de clé par lequel il trie et une clé "ordre" qui est une chaîne indiquant "croissant" ou "décroissant".

sortMultiCompare = (a, b, sorts) => {
    let select = sorts[0].select
    let order = sorts[0].order
    if (a[select] < b[select]) {
        return order == 'ascending' ? -1 : 1
    } 
    if (a[select] > b[select]) {
        return order == 'ascending' ? 1 : -1
    }
    if(sorts.length > 1) {
        let remainingSorts = sorts.slice(1)
        return this.sortMultiCompare(a, b, remainingSorts)
    }
    return 0
}

sortResults = (results, sorts) => {
    return results.sort((a, b) => {
        return this.sortMultiCompare(a, b, sorts)
    })
}

// example inputs
const results = [
    {
        "LastName": "Doe",
        "FirstName": "John",
        "MiddleName": "Bill"
    },
    {
        "LastName": "Doe",
        "FirstName": "Jane",
        "MiddleName": "Bill"
    },
    {
        "LastName": "Johnson",
        "FirstName": "Kevin",
        "MiddleName": "Bill"
    }
]

const sorts = [
    {
        "select": "LastName",
        "order": "ascending"
    },
    {
        "select": "FirstName",
        "order": "ascending"
    },
    {
        "select": "MiddleName",
        "order": "ascending"
    }    
]

// call the function like this:
let sortedResults = sortResults(results, sorts)

2

Une façon dynamique de faire cela avec PLUSIEURS touches:

  • filtrer les valeurs uniques de chaque col / clé de tri
  • mettre en ordre ou inverser
  • ajouter des poids width zeropad pour chaque objet en fonction des valeurs des clés indexOf (value)
  • trier à l'aide de poids calculés

entrez la description de l'image ici

Object.defineProperty(Array.prototype, 'orderBy', {
value: function(sorts) { 
    sorts.map(sort => {            
        sort.uniques = Array.from(
            new Set(this.map(obj => obj[sort.key]))
        );

        sort.uniques = sort.uniques.sort((a, b) => {
            if (typeof a == 'string') {
                return sort.inverse ? b.localeCompare(a) : a.localeCompare(b);
            }
            else if (typeof a == 'number') {
                return sort.inverse ? (a < b) : (a > b ? 1 : 0);
            }
            else if (typeof a == 'boolean') {
                let x = sort.inverse ? (a === b) ? 0 : a? -1 : 1 : (a === b) ? 0 : a? 1 : -1;
                return x;
            }
            return 0;
        });
    });

    const weightOfObject = (obj) => {
        let weight = "";
        sorts.map(sort => {
            let zeropad = `${sort.uniques.length}`.length;
            weight += sort.uniques.indexOf(obj[sort.key]).toString().padStart(zeropad, '0');
        });
        //obj.weight = weight; // if you need to see weights
        return weight;
    }

    this.sort((a, b) => {
        return weightOfObject(a).localeCompare( weightOfObject(b) );
    });

    return this;
}
});

Utilisation:

// works with string, number and boolean
let sortered = your_array.orderBy([
    {key: "type", inverse: false}, 
    {key: "title", inverse: false},
    {key: "spot", inverse: false},
    {key: "internal", inverse: true}
]);

entrez la description de l'image ici


1

C'est ce que j'utilise

function sort(a, b) {
    var _a = "".concat(a.size, a.glow);
    var _b = "".concat(b.size, b.glow);
    return _a < _b;
}

concat les deux éléments sous forme de chaîne et ils seront triés par une valeur de chaîne. Si vous le souhaitez, vous pouvez envelopper _a et _b avec parseInt pour les comparer sous forme de nombres si vous savez qu'ils seront numériques.


1

Voici la solution pour le cas, lorsque vous avez une clé de tri prioritaire, qui peut ne pas exister dans certains éléments particuliers, vous devez donc trier par clés de secours.

Un exemple de données d'entrée ( id2 est la clé de tri prioritaire):

const arr = [
    {id: 1},
    {id: 2, id2: 3},
    {id: 4},
    {id: 3},
    {id: 10, id2: 2},
    {id: 7},
    {id: 6, id2: 1},
    {id: 5},
    {id: 9, id2: 2},
    {id: 8},
];

Et la sortie devrait être:

[ { id: 6, id2: 1 },
  { id: 9, id2: 2 },
  { id: 10, id2: 2 },
  { id: 2, id2: 3 },
  { id: 1 },
  { id: 3 },
  { id: 4 },
  { id: 5 },
  { id: 7 },
  { id: 8 } ]

La fonction comparateur sera comme:

arr.sort((a,b) => {
  if(a.id2 || b.id2) {
    if(a.id2 && b.id2) {
      if(a.id2 === b.id2) {
        return a.id - b.id;
      }
      return a.id2 - b.id2;
    }
    return a.id2 ? -1 : 1;
  }
  return a.id - b.id
});

PS Dans le cas où .id de .id2 peut être des zéros, pensez à utiliser typeof.


0
grouperArray.sort(
  function(a,b){return a.gsize == b.gsize ? a.glow - b.glow : a.gsize - b.gsize}
);

0
grouperArray.sort(function (a, b) {
    var aSize = a.gsize;
    var bSize = b.gsize;
    if (aSize !== aSize)
        return aSize - bSize;
    return a.glow - b.glow;
});

pas testé, mais je pense que cela devrait fonctionner.


0

Dans mon cas, je trie la liste des notifications par paramètre «important» et par «date»

  • étape 1: je filtre les notifications par `` important '' et non important

    let importantNotifications = notifications.filter(
            (notification) => notification.isImportant);
    
      let unImportantNotifications = notifications.filter(
            (notification) => !notification.isImportant);
    
  • étape 2: je les trie par date

      sortByDate = (notifications) => {
      return notifications.sort((notificationOne, notificationTwo) => {
        return notificationOne.date - notificationTwo.date;
      });
    };
    
  • étape 3: fusionnez-les

    [
        ...this.sortByDate(importantNotifications),
        ...this.sortByDate(unImportantNotifications),
      ];
    
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.