题 对JavaScript对象数组进行排序


我使用Ajax读取以下对象并将它们存储在一个数组中:

var homes = [
    {
        "h_id": "3",
        "city": "Dallas",
        "state": "TX",
        "zip": "75201",
        "price": "162500"
    }, {
        "h_id": "4",
        "city": "Bevery Hills",
        "state": "CA",
        "zip": "90210",
        "price": "319250"
    }, {
        "h_id": "5",
        "city": "New York",
        "state": "NY",
        "zip": "00010",
        "price": "962500"
    }
];

如何创建一个函数来对象进行排序 price 物业 上升  要么   仅使用JavaScript订购?


1039
2018-06-11 04:12


起源




答案:


按价格按升序排序房屋:

homes.sort(function(a, b) {
    return parseFloat(a.price) - parseFloat(b.price);
});

或者在ES6版本之后:

homes.sort((a, b) => parseFloat(a.price) - parseFloat(b.price));

可以找到一些文档 这里


1330
2018-06-11 04:33



您可以使用 string1.localeCompare(string2) 用于字符串比较 - bradvido
请记住 localeCompare() 是的情况 麻木不仁。如果您想要区分大小写,可以使用 (string1 > string2) - (string1 < string2)。布尔值被强制为整数0和1以计算差异。 - Don Kirkby
有没有办法将参数传递给compare函数?想要将这个作为一个可重用的函数,我可以通过它来对对象进行排序吗? - jlbriggs
@jlbriggs:看 Triptych的回答如下 - Stobor
感谢@Pointy的更新,我不记得遇到这个问题,但也许这种行为在过去几年中发生了变化。无论如何 localeCompare()文件 表明您可以明确说明是否需要区分大小写,数字排序和其他选项。 - Don Kirkby


这是一个更灵活的版本,允许您创建 可重复使用的排序函数,并按任何字段排序。

var sort_by = function(field, reverse, primer){

   var key = primer ? 
       function(x) {return primer(x[field])} : 
       function(x) {return x[field]};

   reverse = !reverse ? 1 : -1;

   return function (a, b) {
       return a = key(a), b = key(b), reverse * ((a > b) - (b > a));
     } 
}

现在您可以随意按任意字段排序......

var homes = [{

   "h_id": "3",
   "city": "Dallas",
   "state": "TX",
   "zip": "75201",
   "price": "162500"

}, {

   "h_id": "4",
   "city": "Bevery Hills",
   "state": "CA",
   "zip": "90210",
   "price": "319250"

}, {

   "h_id": "5",
   "city": "New York",
   "state": "NY",
   "zip": "00010",
   "price": "962500"

}];

// Sort by price high to low
homes.sort(sort_by('price', true, parseInt));

// Sort by city, case-insensitive, A-Z
homes.sort(sort_by('city', false, function(a){return a.toUpperCase()}));

624
2018-06-11 04:11



nickb - 你误读了代码。 sort_by 在O(1)中运行,并返回内置排序(O(N log N))使用的函数来比较列表中的项目。总复杂度为O(n log n)* O(1),它减少到O(n log n),或者与快速排序相同。 - Triptych
好主意!一些问题:1-A左括号似乎在错误的地方。 2 - 设置反向看起来反向:) 3线中断似乎导致问题。总的来说,不应该是那个单线 return (A < B ? -1 : (A > B ? 1 : 0)) * [1,-1][+!!reverse]; ? - Halil Özgür
这是这段代码的工作jsfiddle vesrion: jsfiddle.net/dFNva/1 - Blake Mills
我刚刚找到了解释: + 将布尔值转换为数字; !! 将非布尔值转换为布尔值。 (dreaminginjavascript.wordpress.com/2008/07/04/28)所以, [+!!reverse] 提供索引 [-1,1] 数组评估为 [-1,1][0] 要么 [-1,1][1],评估为 -1 要么 1。这太棒了,但令人困惑。 - gfullam
这是一个基于@Blake Mills小提琴的小提琴: jsfiddle.net/gfullam/sq9U7 |它修复了Abby注意到的bug,并使用Crockford方法通过函数调用作为选项传递另一种类型来实现AlanJames请求的“then by”排序。 - gfullam


要对它进行排序,您需要创建一个带有两个参数的比较器函数。然后使用该比较器函数调用sort函数,如下所示:

// a and b are object elements of your array
function mycomparator(a,b) {
  return parseInt(a.price, 10) - parseInt(b.price, 10);
}
homes.sort(mycomparator);

如果要对升序进行排序,请在减号的每一侧切换表达式。


127
2018-06-11 04:14



这是对内置数组排序方法的引用 - w3schools.com/jsref/jsref_sort.asp - Kevin Hakanson
对我来说,升序排序采用最初编码的方式:a.price - b.price - dmonopoly
这里有一个实际解释主题的参考,而不是说“它太复杂了,你无论如何都不会理解它”: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/... - Roland Illig
parseInt 与价格一起使用可能是一个坏主意。它会准确地排序非整数吗? (15.10或15.15)。我用了 parseFloat 代替。 - BeetleJuice


对于字符串排序,如果有人需要它,

var dataArr = {  

    "hello": [{
    "id": 114,
    "keyword": "zzzzzz",
    "region": "Sri Lanka",
    "supportGroup": "administrators",
    "category": "Category2"
}, {
    "id": 115,
    "keyword": "aaaaa",
    "region": "Japan",
    "supportGroup": "developers",
    "category": "Category2"
}]

};
var sortArray = dataArr['hello'];
sortArray.sort(function(a,b) {
    if ( a.region < b.region )
        return -1;
    if ( a.region > b.region )
        return 1;
    return 0;
} );

34
2018-06-11 04:14



不知道为什么我的答案被标记为社区维基帖子:-( - Ishan Liyanage
我猜这是因为问题本身被标记为社区维基。 - trichoplax
显然, 您 成为CW帖子:“Ishan Liyanage的Post Made Community Wiki” - Léo Lam
我自己用Google搜索了这个问题。谢谢你自己过去! :-) - Ishan Liyanage


如果你有 ES6 您可以使用兼容的浏览器:

升序和降序排序顺序之间的差异是比较函数返回的值的符号:

var ascending = homes.sort((a, b) => Number(a.price) - Number(b.price));
var descending = homes.sort((a, b) => Number(b.price) - Number(a.price));

这是一个有效的代码片段:

var homes = [{
  "h_id": "3",
  "city": "Dallas",
  "state": "TX",
  "zip": "75201",
  "price": "162500"
}, {
  "h_id": "4",
  "city": "Bevery Hills",
  "state": "CA",
  "zip": "90210",
  "price": "319250"
}, {
  "h_id": "5",
  "city": "New York",
  "state": "NY",
  "zip": "00010",
  "price": "962500"
}];

homes.sort((a, b) => Number(a.price) - Number(b.price));
console.log("ascending", homes);

homes.sort((a, b) => Number(b.price) - Number(a.price));
console.log("descending", homes);


28
2017-07-12 14:59



它为降序和升序函数返回相同的数组。我闻到了一个臭虫。 - Hynek
感谢您的评论@Hynek。我修改了样本以显示 sort() function修改原始数组。 - Stephen Quan


你想用Javascript对它进行排序,对吧?你想要的是什么 sort() 功能。在这种情况下,您需要编写比较器函数并将其传递给 sort(),所以这样的事情:

function comparator(a, b) {
    return parseInt(a["price"], 10) - parseInt(b["price"], 10);
}

var json = { "homes": [ /* your previous data */ ] };
console.log(json["homes"].sort(comparator));

比较器从阵列中的每个嵌套哈希中取出一个,并通过检查“price”字段来决定哪一个更高。


22



那不是一个正确的比较器 - Bergi
parseInt 与价格一起使用可能是一个坏主意。它会准确地排序非整数吗? (15.10或15.15)。我用了 parseFloat 代替。 - BeetleJuice


我建议 GitHub:数组sortBy  - 最好的实施 sortBy 使用的方法 施瓦茨变换

但是现在我们将尝试这种方法 要点:sortBy-old.js
让我们创建一个方法来排序能够通过某些属性排列对象的数组。

创建排序功能

var sortBy = (function () {
  var toString = Object.prototype.toString,
      // default parser function
      parse = function (x) { return x; },
      // gets the item to be sorted
      getItem = function (x) {
        var isObject = x != null && typeof x === "object";
        var isProp = isObject && this.prop in x;
        return this.parser(isProp ? x[this.prop] : x);
      };

  /**
   * Sorts an array of elements.
   *
   * @param  {Array} array: the collection to sort
   * @param  {Object} cfg: the configuration options
   * @property {String}   cfg.prop: property name (if it is an Array of objects)
   * @property {Boolean}  cfg.desc: determines whether the sort is descending
   * @property {Function} cfg.parser: function to parse the items to expected type
   * @return {Array}
   */
  return function sortby (array, cfg) {
    if (!(array instanceof Array && array.length)) return [];
    if (toString.call(cfg) !== "[object Object]") cfg = {};
    if (typeof cfg.parser !== "function") cfg.parser = parse;
    cfg.desc = !!cfg.desc ? -1 : 1;
    return array.sort(function (a, b) {
      a = getItem.call(cfg, a);
      b = getItem.call(cfg, b);
      return cfg.desc * (a < b ? -1 : +(a > b));
    });
  };

}());

设置未排序的数据

var data = [
  {date: "2011-11-14T16:30:43Z", quantity: 2, total: 90,  tip: 0,   type: "tab"},
  {date: "2011-11-14T17:22:59Z", quantity: 2, total: 90,  tip: 0,   type: "Tab"},
  {date: "2011-11-14T16:28:54Z", quantity: 1, total: 300, tip: 200, type: "visa"},
  {date: "2011-11-14T16:53:41Z", quantity: 2, total: 90,  tip: 0,   type: "tab"},
  {date: "2011-11-14T16:48:46Z", quantity: 2, total: 90,  tip: 0,   type: "tab"},
  {date: "2011-11-14T17:25:45Z", quantity: 2, total: 200, tip: 0,   type: "cash"},
  {date: "2011-11-31T17:29:52Z", quantity: 1, total: 200, tip: 100, type: "Visa"},
  {date: "2011-11-14T16:58:03Z", quantity: 2, total: 90,  tip: 0,   type: "tab"},
  {date: "2011-11-14T16:20:19Z", quantity: 2, total: 190, tip: 100, type: "tab"},
  {date: "2011-11-01T16:17:54Z", quantity: 2, total: 190, tip: 100, type: "tab"},
  {date: "2011-11-14T17:07:21Z", quantity: 2, total: 90,  tip: 0,   type: "tab"},
  {date: "2011-11-14T16:54:06Z", quantity: 1, total: 100, tip: 0,   type: "Cash"}
];

使用它

按顺序排列数组 "date" 如 String

// sort by @date (ascending)
sortBy(data, { prop: "date" });

// expected: first element
// { date: "2011-11-01T16:17:54Z", quantity: 2, total: 190, tip: 100, type: "tab" }

// expected: last element
// { date: "2011-11-31T17:29:52Z", quantity: 1, total: 200, tip: 100, type: "Visa"}

如果要忽略区分大小写,请设置 parser 回电话:

// sort by @type (ascending) IGNORING case-sensitive
sortBy(data, {
    prop: "type",
    parser: (t) => t.toUpperCase()
});

// expected: first element
// { date: "2011-11-14T16:54:06Z", quantity: 1, total: 100, tip: 0, type: "Cash" }

// expected: last element
// { date: "2011-11-31T17:29:52Z", quantity: 1, total: 200, tip: 100, type: "Visa" }

如果你想转换 "date" 领域为 Date 类型:

// sort by @date (descending) AS Date object
sortBy(data, {
    prop: "date",
    desc: true,
    parser: (d) => new Date(d)
});

// expected: first element
// { date: "2011-11-31T17:29:52Z", quantity: 1, total: 200, tip: 100, type: "Visa"}

// expected: last element
// { date: "2011-11-01T16:17:54Z", quantity: 2, total: 190, tip: 100, type: "tab" }

在这里你可以玩代码: jsbin.com/lesebi

谢谢 @Ozesh 根据他的反馈,该问题与财产有关 falsy 价值是固定的。


20



我添加了一个新的更强大的实现,允许多种排序,例如 field1 ASC之后 field2 DESC,之后 field3 DESC。新的 sortBy 方法是一种实现方式 施瓦茨变换 你可以在这里找到它: 要点:sortBy.js - jherax
当字段为空时,这似乎会中断。 - TSNev
@TSNev你能提供一个例子(jsfiddle,plunkr等)吗?我试图复制它没有成功, null 值在数组末尾排序。 - jherax
如果您正在对数字进行排序,并且在对象数组之间遇到“0”,您可能会注意到上面的代码中断了。以下是对此的快速修复: var checkNaN = function (value) { return Number.isNaN(Number(value)) ? 0 : value; }其次是:return function(array,o){.... a = _getItem.call(o,a); a = checkNaN(a);  b = _getItem.call(o,b); b = checkNaN(b); return o.desc *(a <b?-1:+(a> b)); }); - Ozesh
感谢您的反馈@Ozesh, sortBy 上面的版本已被弃用:)我已经为排序数组编写了一个新的更强大的实现。检查 这个要点:sortBy - jherax