Une façon d'étendre la méthode array.sort () de javascript pour accepter un autre paramètre?

J'essaie de trier un ensemble d'objets. Je préfère ne pas écrire une méthode de tri personnalisée pour chaque attribut.

Est-ce que de toute façon, je pourrais étendre la méthode array.sort() pour accepter un paramètre supplémentaire, décrivant l'attribut à trier? Par exemple,

 array.sort(function(a, b, attr) { return a.attr - b.attr; }, 'name'); 

Écrivez un générateur de fonctions qui accepte un nom de propriété:

 function propComparator(prop) { return function(a, b) { return a[prop] - b[prop]; } } arr.sort(propComparator('name')); 

Vous pouvez également enregistrer les trieurs pour une utilisation ultérieure, directement ou en tant que paramètres:

 var compareNames = propComparator('name'); var compareFoos = propComparator('foo'); ... arr.sort(compareNames); takesComparator(compareFoos); 

Mise à jour pour ES6, et faites-le pour qu'il fonctionne réellement avec différents types.

Notez que le sort classé sur place, ce qui peut ou non être souhaitable.

 const arr = [ { name: 'John', age: 92 }, { name: 'Dave', age: 42 }, { name: 'Justin', age: 3 } ] const propComparator = (propName) => (a, b) => a[propName] == b[propName] ? 0 : a[propName] < b[propName] ? -1 : 1 arr.sort(propComparator('name')) console.log("By name", arr) arr.sort(propComparator('age')) console.log("By age", arr) 

C'est ce que vous cherchez?

 function sortByProperty(array, propertyName) { return array.sort(function (a, b) { return a[propertyName] - b[propertyName]; }); } var sortedByName = sortByProperty(myArray, "name"); 

Est-ce que de toute façon, je pourrais étendre la méthode intégrée array.sort () pour accepter un paramètre supplémentaire

Toutes les réponses ci-dessus sont bonnes. Mais j'ai pensé à ajouter des informations sur les fonctions partielles

Pour plus d'informations, voir bind dans MDN et partielle Fonction ou John Resig – fonction partielle

Exemple de MDN:

 function list() { return Array.prototype.slice.call(arguments); } var list1 = list(1, 2, 3); // [1, 2, 3] // Create a function with a preset leading argument var leadingThirtysevenList = list.bind(undefined, 37); var list2 = leadingThirtysevenList(); // [37] var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3] 

Voici un exemple de Google Closure

 goog.partial = function(fn, var_args) { var args = Array.prototype.slice.call(arguments, 1); return function() { // Prepend the bound arguments to the current arguments. var newArgs = Array.prototype.slice.call(arguments); newArgs.unshift.apply(newArgs, args); return fn.apply(this, newArgs); }; }; 

Utiliser cette fonction

  var fn=goog.partial(numberCompare,sortField,sortDirection); myarray.sort (fn); var numberCompare = function (sortField,sortDirection,value1,value2){ // sort code goes here } 

Utilisez des prototypes pour comparer correctement les chaînes et les nombres

 String.prototype.compare = function(x) { if(!x.charCodeAt) return -1; var result = this.charCodeAt(0)-x.charCodeAt(0); if(!result) return this.substr(1).compare(x.substr(1)); return result; } Array.prototype.sortAttr = function(attr,reverse) { var sorter = function(a,b) { var aa = a[attr]; var bb = b[attr]; if(aa+0==aa && bb+0==bb) return aa-bb; else if(aa.compare) return aa.compare(bb); // aa-bb does not work return 0; } this.sort(function(a,b) { var result = sorter(a,b); if(reverse) result*= -1; return result; }); }; 

Exemple

 var data = [ {name: "Josh", age: 18}, {name: "John", age: 17}, {name: "Bob", age: 20}, {name: 0, age: "error"} ]; data.sortAttr("name"); // data is now sorted by name 

Actuellement, l'étendre

Afin d'étendre réellement Array.prototype.sort , nous avons quelques options:

  • Mutation de sa signature
  • Trier par multiplicité en utilisant les décorateurs | Adaptateurs (modèle parent: emballage )

J'étais dans votre même bateau et j'ai décidé d'utiliser la 2ème approche:

 private sortAddresses = (a, b) => { let iPrimeFlag = this.sortAddressesByPrimaryFlag(a, b); let iAlphaNum = this.sortAddressesByAlphaNum(a, b); if (iPrimeFlag === 1) return 1; else return iAlphaNum; }; private sortAddressesByPrimaryFlag(a, b) { if (b.primaryFlag > a.primaryFlag) return 1; if (b.primaryFlag < a.primaryFlag) return -1; return 0; } private sortAddressesByAlphaNum(a, b) { let aAddress = this.$.formatAddress(a); let bAddress = this.$.formatAddress(b); if (aAddress > bAddress) return 1; if (aAddress < bAddress) return -1; return 0; } 

Intention

this.addresses.sort(this.sortAddresses) dans plusieurs endroits et j'aimerais que mon ChangeCost soit bas – en particulier, sachant que nous pourrions avoir des exigences pour trier encore plus d'heuristiques .

Donc, afin de suivre les Deux règles du pouce de The Gang of Four

Programmer vers une interface, pas une implémentation.

et

Encapsule ce qui varie.

– J'ai décidé de garder ma signature la même et d'envelopper ma méthode originale.

Il serait utile que nous ne devions pas passer à travers et changer chaque ligne où nous this.addresses.sort . Au lieu de cela, nous aimerions pouvoir ajouter un nombre indéfini de "heuristiques" triées à l'action de tri.

Le but est de prioriser les objets d'adresse dont primaryFlag est 'Y' , puis prendre la chaîne d'adresse – '0000 Some St, #0000, City, ST 00000' – et trier ces paramètres alphanumériques. Puisque 'Y' est > 'N' , nous aimerions le déplacer dans la liste, visuellement, en abaissant son index. Le tri de la chaîne d'adresse alphanumérique indique que si 'Colorado' est > 'Alabama' , alors nous devrions baisser le 'Colorado' dans la liste visuellement en augmentant son indice.

Usage

Ceci est utilisé pour trier les adresses par différentes valeurs. Une valeur, primaryFlag , est de désigner si c'est l'adresse par défaut [seulement]; Dans mon cas, primaryFlag est une attaque de 'Y' ou 'N' , pas un boolean (demandez à mes coéquipiers Back-End pourquoi dans le monde?). L'autre valeur, this.$.formatAddress(a|b) prend cette adresse [object Object] 's – a et b – et appelle formatAddress off of my Sandbox this.$ .

La ligne if (iPrimeFlag === 1) return 1; Est en train de dire: "n'importe quand primaryFlag est 1, il suffit de coller cela vers la tête (début) du tableau, sinon faire tout ce que l'heuristique alphanumérique décide", ce qui nous permet de prioriser par une heuristique en reculant sur une autre.

Notez également que .bind(undefined, 'prop') n'est pas utilisé dans mon code actuel car je n'en ai pas besoin; Ceci est juste ici à des fins démonstratives .

Maintenant, je sais que je suis cette personne qui a fourni un certain typeScript – rappelez-vous si vous ne comprenez pas ce qui se passe dans ce code 🙂

À votre santé!