我正在尝试对一组对象进行排序。我不想为每个属性编写自定义排序方法。
无论如何我可以扩展内置的array.sort()
方法来接受一个额外的参数,描述要排序的属性吗?如,
array.sort(function(a, b, attr) { return a.attr - b.attr; }, 'name');
答案 0 :(得分:101)
编写一个接受属性名称的函数生成器:
function propComparator(prop) {
return function(a, b) {
return a[prop] - b[prop];
}
}
arr.sort(propComparator('name'));
您也可以保存分拣机以供以后使用,直接或作为参数:
var compareNames = propComparator('name');
var compareFoos = propComparator('foo');
...
arr.sort(compareNames);
takesComparator(compareFoos);
针对ES6进行了更新,并使其实际上适用于不同类型。
请注意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)
答案 1 :(得分:8)
这是你要找的吗?
function sortByProperty(array, propertyName) {
return array.sort(function (a, b) {
return a[propertyName] - b[propertyName];
});
}
var sortedByName = sortByProperty(myArray, "name");
答案 2 :(得分:4)
使用原型正确比较字符串和数字
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;
});
};
实施例
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
答案 3 :(得分:3)
无论如何我可以扩展内置的array.sort()方法以接受额外的参数
以上所有答案都很好。但我想添加一些关于部分功能的信息
有关详细信息,请参阅MDN和partial Function或John Resig中的绑定 - partial function
来自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]
的示例
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);
};
};
使用此功能
var fn=goog.partial(numberCompare,sortField,sortDirection);
myarray.sort (fn);
var numberCompare = function (sortField,sortDirection,value1,value2){
// sort code goes here
}
答案 4 :(得分:1)
万一有人需要升序,这是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))
答案 5 :(得分:-1)
为了实际扩展Array.prototype.sort
,我们有几个选项:
我在同一条船上并决定采用第二种方法:
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;
}
我已经在多个地方拨打了this.addresses.sort(this.sortAddresses)
,并且我希望将 ChangeCost 保持在低水平 - 特别是,知道这一点我们可能会要求对甚至更多启发式进行排序。
所以,为了遵循四人帮的两个&#39; -
编程到接口,而不是实现。
和
封装各种不同的内容。
- 我决定保持我的签名并保存原始方法。
如果我们没有必要通过并更改我们调用this.addresses.sort
的每一行,那将非常有用。相反,我们希望能够添加无限期数量的排序&#34;启发式&#34;对排序的行为。
目标是确定primaryFlag
为'Y'
的地址对象的优先级,然后取地址字符串 - '0000 Some St, #0000, City, ST 00000'
- 并按字母数字排序。由于'Y'
为>
'N'
,我们希望通过降低索引,在视觉上将其向上移动。按地理字母排序地址字符串表示如果'Colorado'
为>
'Alabama'
,那么我们应该通过增加索引来直观地将列表中的'Colorado'
降低
这用于按不同的值对地址进行排序。一个值primaryFlag
表示它是否是[唯一]默认地址;在我的情况下,primaryFlag
是'Y'
或'N'
的刺痛,而不是布尔(问我的后端队友为什么在世界上?)。另一个值this.$.formatAddress(a|b)
采用这些地址[object Object]
&#39; s - a
和b
- 并从我的formatAddress >沙盒 this.$
。
行if (iPrimeFlag === 1) return 1;
说,&#34;只要primaryFlag为1,只是朝着数组的头部(开头)碰撞,否则,做任何字母数字启发式决定&#34;,这允许我们优先排序通过一个启发式,同时回到另一个。
另请注意,.bind(undefined, 'prop')
不在我的实际代码中使用,因为我不需要它; 这仅用于演示目的。
现在,我知道我提供了一些 TypeScript 的人知道你是否知道这段代码中发生了什么:)
干杯!