有什么方法可以扩展javascript的array.sort()方法来接受另一个参数?

时间:2011-12-16 17:05:15

标签: javascript

我正在尝试对一组对象进行排序。我不想为每个属性编写自定义排序方法。

无论如何我可以扩展内置的array.sort()方法来接受一个额外的参数,描述要排序的属性吗?如,

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

6 个答案:

答案 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]

这是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);
  };
};

使用此功能

    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,我们有几个选项:

  • 改变其签名
  • 使用装饰器 |进行多重排序适配器(父模式: Wrapper

我在同一条船上并决定采用第二种方法:

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 - ab - 并从我的formatAddress >沙盒 this.$

if (iPrimeFlag === 1) return 1;说,&#34;只要primaryFlag为1,只是朝着数组的头部(开头)碰撞,否则,做任何字母数字启发式决定&#34;,这允许我们优先排序通过一个启发式,同时回到另一个。

另请注意,.bind(undefined, 'prop') 在我的实际代码中使用,因为我不需要它; 这仅用于演示目的

现在,我知道我提供了一些 TypeScript 的人知道你是否知道这段代码中发生了什么:)

干杯!