【问题标题】:Sort array of objects based on multiple properties根据多个属性对对象数组进行排序
【发布时间】:2017-02-23 00:44:41
【问题描述】:

我正在尝试根据对象内的任意属性对对象数组进行排序。 我编写了以下完美运行的代码。

var customSort = function(data, sortBy, order) {
  if (!(data && sortBy)) {
    throw new Error('Specify the data source and atleast one property to sort it by');
  }
  if (!Array.isArray(data)) {
    throw new Error('Specify the data source as an array');
  }
  order = order || 'asc';

  function performSort(order, sortBy) {
    return data.sort(function(a, b) {
      var A = parse(a, sortBy);
      var B = parse(b, sortBy);
      if (A < B) {
        return order === 'asc' ? -1 : 1;
      } else if (A > B) {
        return order === 'asc' ? 1 : -1;
      } else {
        return 0;
      }
    });
  }

  function parse(data, sortBy) {
    var sortParams = sortBy.split('.');
    var latestValue = data;
    for (var i = 0; i < sortParams.length; i++) {
      latestValue = latestValue[sortParams[i]];
    }
    if (!latestValue) {
      throw new Error('Check the \'sortBy\' parameter. Unreachable parameter in \'sortBy\'');
    }
    if (typeof latestValue === 'string') {
      return latestValue.toLowerCase();
    } else {
      return latestValue;
    }
  }

  return performSort(order, sortBy);
};

var lonelyData = [{
  a: {
    b: 2
  }
}, {
  a: {
    b: 1
  }
}, {
  a: {
    b: 9
  }
}, {
  a: {
    b: 7
  }
}, {
  a: {
    b: 4
  }
}, {
  a: {
    b: 2
  }
}, {
  a: {
    b: 1
  }
}];

console.log(customSort(lonelyData, 'a.b'));

在这里提琴:JSFiddle



现在,我正在尝试使用递归按以下方式按多个属性排序:首先,按第一个属性排序,然后在同一属性内,按第二个属性排序,依此类推。为了简单起见,我假设所有属性的顺序相同,即全部增加或全部减少。
我写了这段代码:

var customSort = function(data, sortBy, order) {
  if (!(data && sortBy)) {
    throw new Error('Specify the data source and atleast one property to sort it by');
  }
  if (!Array.isArray(data)) {
    throw new Error('Specify the data source as an array');
  }
  if (!Array.isArray(sortBy)) {
    sortBy = [sortBy];
  }
  order = order || 'asc';

  function performSort(order, sortBy) {
    return data.sort(function(a, b) {
      function nestedSort() {
        var highestOrder = sortBy[0];
        var A = parse(a, highestOrder);
        var B = parse(b, highestOrder);
        if (A < B) {
          return order === 'asc' ? -1 : 1;
        } else if (A > B) {
          return order === 'asc' ? 1 : -1;
        } else {
          sortBy.shift();
          nestedSort();
        }
      }
      return nestedSort();
    });
  }

  function parse(data, sortBy) {
    var sortParams = sortBy.split('.');
    var latestValue = data;
    for (var i = 0; i < sortParams.length; i++) {
      latestValue = latestValue[sortParams[i]];
    }
    if (!latestValue) {
      throw new Error('Check the \'sortBy\' parameter. Unreachable property passed in \'sortBy\'');
    }
    if (typeof latestValue === 'string') {
      return latestValue.toLowerCase();
    } else {
      return latestValue;
    }
  }

  return performSort(order, sortBy);
};

var lonelyData = [{
  a: {
    b: 2,
    c: 'Z'
  }
}, {
  a: {
    b: 2,
    c: 'A'
  }
}, {
  a: {
    b: 9,
    c: 'Q'
  }
}, {
  a: {
    b: 7,
    c: 'L'
  }
}, {
  a: {
    b: 7,
    c: 'E'
  }
}, {
  a: {
    b: 1,
    c: 'A'
  }
}, {
  a: {
    b: 1,
    c: 'B'
  }
}];

console.log(customSort(lonelyData, ['a.b', 'a.c']));

在这里提琴:JSFiddle


不幸的是,我无法让它工作。我在这里错过了什么?

【问题讨论】:

  • 这里有点迷惑......如果 sortBy 是 [a.b, a.c] 那么你希望数组先按数字排序,然后再按字母排序?
  • @LucasKot-Zaniewski 如果 sortBy 是 [ab, ac] 则数组应按数字排序(基于 ab),然后对于相同的数字值 (ab),数组应按字母顺序排序(基于在交流)。例如,它应该是:[{a : {b: 1, c: 'A'}}, {a : {b: 1, c: 'B'}}, {a : {b: 2, c : 'A'}}, {a : {b: 2, c: 'Z'}} ....... 以此类推] 用于上述测试用例

标签: javascript arrays object recursion javascript-objects


【解决方案1】:
     sortBy.shift();
     nestedSort();

是你的问题。 shift 确实改变了数组,并永远删除了第一项。下次调用比较函数将ab 进行比较时,它将被忽略,很快数组将为空,并且您的比较完全中断。

改为使用简单的循环:

return data.sort(function(a, b) {
  for (var i=0; i<sortBy.length; i++)
    var currentOrder = sortBy[i];
    var A = parse(a, currentOrder);
    var B = parse(b, currentOrder);
    if (A < B) {
      return order === 'asc' ? -1 : 1;
    } else if (A > B) {
      return order === 'asc' ? 1 : -1;
    }
  }
  return 0;
});

【讨论】:

  • 非常感谢。它完美地工作。但是,是否也可以递归?
  • 当然,只需递归i。或者每次都通过sortBy 数组和.slice(1) 递归得到一个没有第一个元素的副本。不要忘记你的基本情况!
猜你喜欢
  • 2015-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-11
  • 2012-10-22
  • 1970-01-01
相关资源
最近更新 更多