【问题标题】:JavaScript sort array by 2 valuesJavaScript 按 2 个值对数组进行排序
【发布时间】:2015-03-16 19:42:41
【问题描述】:

我有一个数组,我想按“id”和“date”从小到大对其进行排序。我怎样才能正确地做到这一点?

例子:

var unsorted = [
    {id: 1, date: "2015-01-18T15:00:00+01:00"}, 
    {id: 1, date: "2015-01-18T14:30:00+01:00"}, 
    {id: 2, date: "2015-01-18T10:00:00+01:00"}, 
    {id: 1, date: "2015-01-18T16:00:00+01:00"}, 
    {id: 3, date: "2015-01-18T14:15:00+01:00"}, 
    {id: 2, date: "2015-01-18T14:00:00+01:00"}
]

应该返回:

var sorted = [
    {id: 1, date: "2015-01-18T14:30:00+01:00"}, 
    {id: 1, date: "2015-01-18T15:00:00+01:00"}, 
    {id: 1, date: "2015-01-18T16:00:00+01:00"}, 
    {id: 2, date: "2015-01-18T10:00:00+01:00"}, 
    {id: 2, date: "2015-01-18T14:00:00+01:00"},
    {id: 3, date: "2015-01-18T14:15:00+01:00"} 
]

【问题讨论】:

  • ummmm 从服务器上的数据库中获取数据时,为什么不使用ORDER BY 对数据进行排序?
  • 嗯,array.sort() 将比较器函数作为参数,所以试试吧。
  • 我尝试了很多变化,但没有找到正确的解决方案,所以这就是我在这里问的原因。
  • 你的意思我做不到
  • @IGRACH 我无法处理来自服务器端的数据,因为我通过 pubnub 等获取这些数据。

标签: javascript arrays list sorting


【解决方案1】:

这里是一个使用 array.sort 的例子:

var arr = [
    {id: 1, date: "2015-01-18T15:00:00+01:00"}, 
    {id: 1, date: "2015-01-18T14:30:00+01:00"}, 
    {id: 2, date: "2015-01-18T10:00:00+01:00"}, 
    {id: 1, date: "2015-01-18T16:00:00+01:00"}, 
    {id: 3, date: "2015-01-18T14:15:00+01:00"}, 
    {id: 2, date: "2015-01-18T14:00:00+01:00"}
];

arr.sort(function(a,b){
    if (a.id == b.id) return a.date.localeCompare(b.date);
    return a.id-b.id;    
});

// test
for (var i in arr) {
    console.log(arr[i]);
}

结果是:

 Object {id: 1, date: "2015-01-18T14:30:00+01:00"}
 Object {id: 1, date: "2015-01-18T15:00:00+01:00"}
 Object {id: 1, date: "2015-01-18T16:00:00+01:00"}
 Object {id: 2, date: "2015-01-18T10:00:00+01:00"}
 Object {id: 2, date: "2015-01-18T14:00:00+01:00"}
 Object {id: 3, date: "2015-01-18T14:15:00+01:00"}

【讨论】:

  • 很好地使用了localeCompare。 +1
  • 请注意,根据日期的格式化方式,比较字符串表示与比较日期的结果不同。示例见 superpuccio 的评论 here
【解决方案2】:

你可以使用.sort():

var unsorted = [
    {id: 1, date: "2015-01-18T15:00:00+01:00"}, 
    {id: 1, date: "2015-01-18T14:30:00+01:00"}, 
    {id: 2, date: "2015-01-18T10:00:00+01:00"}, 
    {id: 1, date: "2015-01-18T16:00:00+01:00"}, 
    {id: 3, date: "2015-01-18T14:15:00+01:00"}, 
    {id: 2, date: "2015-01-18T14:00:00+01:00"}
];

var sorted = unsorted.sort(function(a, b) {
    return a.id == b.id ?
        new Date(a.date) - new Date(b.date) : a.id - b.id;
});

console.log(sorted);

输出:

[ { id: 1, date: '2015-01-18T14:30:00+01:00' },
  { id: 1, date: '2015-01-18T15:00:00+01:00' },
  { id: 1, date: '2015-01-18T16:00:00+01:00' },
  { id: 2, date: '2015-01-18T10:00:00+01:00' },
  { id: 2, date: '2015-01-18T14:00:00+01:00' },
  { id: 3, date: '2015-01-18T14:15:00+01:00' } ]

【讨论】:

  • 关闭,但不完全。问题是按 2 个属性对数组进行排序。
【解决方案3】:

试一试

var sorted = unsorted.sort(function(a, b) {
    return a.id === b.id ?
      Date.parse(a.date) - Date.parse(b.date) :
      a.id - b.id ;
});

解释

如果id字段相等,我们要返回date字段的比较结果。

如果id字段不相等,我们将返回id字段的比较

【讨论】:

    【解决方案4】:

    Array.sort 接受一个带有两个参数的函数来比较数组的两个元素。如果此函数返回负数,则 a 放在 b 之前,如果返回正数,则 a 放在 b 之前,如果返回 0,则它们保持原样。在这里,我按 id 比较它们,如果它们的 ID 相同,则按日期进行比较。

    var unsorted = [{
      id: 1,
      date: "2015-01-18T15:00:00+01:00"
    }, {
      id: 1,
      date: "2015-01-18T14:30:00+01:00"
    }, {
      id: 2,
      date: "2015-01-18T10:00:00+01:00"
    }, {
      id: 1,
      date: "2015-01-18T16:00:00+01:00"
    }, {
      id: 3,
      date: "2015-01-18T14:15:00+01:00"
    }, {
      id: 2,
      date: "2015-01-18T14:00:00+01:00"
    }];
    
    unsorted.sort(function(a, b) {
      if (a.id < b.id)
        return -1;
      else if (a.id > b.id)
        return 1;
      else {
        if (a.date < b.date)
          return -1;
        else if (a.date > b.date)
          return 1;
        else
          return 0;
      }
    });

    【讨论】:

      【解决方案5】:

      分而治之!

      首先将输入数组缩减为 id => 对象的映射,即:

      var dataById = unsorted.reduce(function (soFar, value) {
      	// Initialise the array if we haven't processed this
          // id yet.
          if (soFar[value.id] === undefined) {
              soFar[value.id] = [];
          }
        
          // ad this object to Array.
          soFar[value.id].push(value);
        
          return soFar;
      }, {});

      现在您可以通过循环遍历对象的键对每个数组进行排序,注意这会修改 dataById 映射。

      Object.keys(dataById).forEach(function (id) {
      	dataById[id] = dataById[id].sort();
      });

      最后,您可以将所有数据组合在一起,再次通过迭代地图中的键。请注意,javascript 中的映射(对象)不保证其键的顺序,因此您可能希望在迭代之前先将 id 转储到数组中:

      var ids = Object.keys(dataById).sort();
      
      // Reduce the ids into an Array of data.
      var ids.reduce(function (soFar, value) {
      	return soFar.concat(dataById[id]);
      }, []);

      这不是解决问题的最有效方法,但希望它能在思考过程中为您提供一些帮助。

      【讨论】:

        猜你喜欢
        • 2022-12-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-14
        • 1970-01-01
        • 1970-01-01
        • 2015-05-12
        • 1970-01-01
        相关资源
        最近更新 更多