有什么方法可以扩展 javascript 的 array.sort() 方法以接受另一个参数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8537602/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Any way to extend javascript's array.sort() method to accept another parameter?
提问by danwoods
I'm trying to sort an array of objects. I'd prefer not to write a custom sort method for each attribute.
我正在尝试对一组对象进行排序。我不想为每个属性编写自定义排序方法。
Is there anyway I could extend the built-in array.sort()
method to accept an extra parameter, describing the attribute to sort on? E.g.,
无论如何我可以扩展内置array.sort()
方法来接受一个额外的参数,描述要排序的属性?例如,
array.sort(function(a, b, attr) { return a.attr - b.attr; }, 'name');
回答by Dave Newton
Write a function generator that accepts a property name:
编写一个接受属性名称的函数生成器:
function propComparator(prop) {
return function(a, b) {
return a[prop] - b[prop];
}
}
arr.sort(propComparator('name'));
You can also save the sorters for later use, directly, or as parameters:
您还可以直接或作为参数保存分拣机供以后使用:
var compareNames = propComparator('name');
var compareFoos = propComparator('foo');
...
arr.sort(compareNames);
takesComparator(compareFoos);
Updated for ES6, and make it so it actually works with different types.
针对 ES6 进行了更新,并使其实际适用于不同的类型。
Note that sort
sorts in-place, which may or may not be desirable.
请注意,sort
就地排序,这可能是可取的,也可能是不可取的。
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)
回答by Domenic
Is this what you're looking for?
这是你要找的吗?
function sortByProperty(array, propertyName) {
return array.sort(function (a, b) {
return a[propertyName] - b[propertyName];
});
}
var sortedByName = sortByProperty(myArray, "name");
回答by Jan Turoň
Use prototypes to compare strings and numbers correctly
使用原型正确比较字符串和数字
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; // numbers
else return aa.localeCompare(bb); // strings
}
this.sort(function(a,b) {
var result = sorter(a,b);
if(reverse) result*= -1;
return result;
});
};
Example
例子
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
回答by dekdev
Is there anyway I could extend the built-in array.sort() method to accept an extra parameter
无论如何我可以扩展内置的 array.sort() 方法来接受一个额外的参数
all above answers are good . but i thought of adding some info about partial functions
以上所有答案都很好。但我想添加一些关于部分功能的信息
for more info see bind in MDN and partial Functionor John Resig - partial function
有关更多信息,请参阅 MDN 中的绑定和部分函数或 John Resig -部分函数
Example from MDN :
来自 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]
here is an example from 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);
};
};
to Use this function
使用此功能
var fn=goog.partial(numberCompare,sortField,sortDirection);
myarray.sort (fn);
var numberCompare = function (sortField,sortDirection,value1,value2){
// sort code goes here
}
回答by stallingOne
In case someone needs ascending order, here is DaveNewton's solution with a reverse option
如果有人需要升序,这里是 DaveNewton 的带有反向选项的解决方案
const sorton = (prop, asc=0) => {
if(!asc) return (a, b) => a[prop] == b[prop] ? 0 : a[prop] < b[prop] ? -1 : 1
else return (b, a) => a[prop] == b[prop] ? 0 : a[prop] < b[prop] ? -1 : 1
}
arr.sort(propComparator('age', 1))
arr.sort(propComparator('age', 1))
回答by Cody
Actually Extending It
实际上扩展它
In order to actually extend Array.prototype.sort
, we have a couple options:
为了实际扩展Array.prototype.sort
,我们有几个选择:
- Mutate its signature
- Sort in multiplicity using Decorators| Adapters( Parent Pattern: Wrapper)
- 改变它的签名
- 使用装饰器进行多重排序| 适配器(父模式:包装器)
I was in your same boat and decided to utilize the 2nd approach:
我在同一条船上,并决定使用第二种方法:
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;
}
Intent
意图
I'm already calling this.addresses.sort(this.sortAddresses)
in several placesand I'd like to keep my ChangeCostlow -- especially, knowing that we may get requirements to sort on even more heuristics.
我已经this.addresses.sort(this.sortAddresses)
在几个地方打电话了,我想保持我的ChangeCost低——尤其是,知道我们可能需要对更多的启发式进行排序。
So, in order to follow The Gang of Four's Two 'Rules of Thumb'--
所以,为了遵循四人帮的两个“经验法则”——
Program to an interface, not an implementation.
编程到接口,而不是实现。
and
和
Encapsulate what varies.
封装不同的内容。
-- I decided to keep my signaturethe same and wrap my original method.
-- 我决定保持我的签名不变并包装我原来的方法。
It would be useful if we didn't have to go through and change each line where we invoke this.addresses.sort
. Instead, we'd like to be able to add an indefinitenumber of sorting "heuristics" to the action of sorting.
如果我们不必遍历并更改我们调用的每一行,那将会很有用this.addresses.sort
。相反,我们希望能够将无限数量的排序“启发式”添加到排序操作中。
The goal is to prioritize address objects whose primaryFlag
is 'Y'
and then take the address string -- '0000 Some St, #0000, City, ST 00000'
-- and sort these alphanumerically. Since 'Y'
is >
'N'
, we'd like to move it upin the list, visually, by lowering its index. Sorting the address string alphanumerically says that if 'Colorado'
is >
'Alabama'
, then we should bump 'Colorado'
downin the list visually by increasing its index.
我们的目标是优先地址对象,其primaryFlag
是'Y'
再乘地址字符串- '0000 Some St, #0000, City, ST 00000'
-和整理这些字母数字。由于'Y'
is >
'N'
,我们希望通过降低其索引将其在列表中向上移动,在视觉上。对地址字符串按字母数字排序表示如果'Colorado'
是>
'Alabama'
,那么我们应该通过增加它的索引来直观地在列表中'Colorado'
向下移动。
Usage
用法
This is used for sorting Addressesby different values. One value, primaryFlag
, is to denote if its the [ only ] default address; in my case, primaryFlag
is a sting of 'Y'
or 'N'
, not a boolean(ask my Back-End teammates why in the world?). The other value, this.$.formatAddress(a|b)
, takes these address [object Object]
's -- a
and b
-- and invokes formatAddress
off of my Sandboxthis.$
.
这用于按不同值对地址进行排序。一个值 ,primaryFlag
表示它是否是 [ 唯一 ] 默认地址;在我的情况下,primaryFlag
是'Y'
or的刺痛'N'
,而不是布尔值(问我的后端队友为什么会这样?)。另一个值 ,this.$.formatAddress(a|b)
接受这些地址[object Object]
-a
和b
- 并formatAddress
从我的沙箱中调用this.$
。
The line if (iPrimeFlag === 1) return 1;
is saying, "anytime primaryFlag is 1, just bump that toward the head (beginning) of the array, otherwise, do whatever the alphanumeric heuristic decides", which allows us to prioritizeby one heuristic while falling back on another.
这条线if (iPrimeFlag === 1) return 1;
是说,“任何时候 primaryFlag 为 1,只需将它撞向数组的头部(开始),否则,执行字母数字启发式决定的任何事情”,这使我们可以通过一个启发式确定优先级,同时退回到另一个。
Also note, .bind(undefined, 'prop')
is notbeing used in my actual code as I don't need it; this is just here for demonstrative purposes.
还要注意,.bind(undefined, 'prop')
是不是被我的实际代码作为我并不需要它; 这只是为了演示目的。
Now, I know I'm that person who provided some TypeScript-- lemme know if you don't understand what's happening in this code :)
现在,我知道我就是提供一些TypeScript 的人——如果你不明白这段代码中发生了什么,我知道:)
Cheers!
干杯!