【问题标题】:es6: Sorting an array of objects with a conditional statementes6:使用条件语句对对象数组进行排序
【发布时间】:2016-10-27 16:52:14
【问题描述】:

我在我的对象数组上使用排序数组原型函数——按“min”键排序

function setStatesOrder(stateOrderArr){

   return stateOrderArr.sort((x,y) => x.min - y.min);

}

但现在我想将对象数组中的第一个对象排除在排序之外。它具有“状态”键和“美国”值所以我试图排除这个对象,但它不起作用:

  function setStatesOrder(stateOrderArr){

     return stateOrderArr.sort((x,y) => {if(x.state !=="U.S."){x.min - y.min}});

  }


stateOrderArr  = [
{state: "U.S.", max: 1, min: -14, stateID: "US", final: 0.3},
{state: "Ohio", max: 5, min: -2, stateID: "OH", final: 5},
{state: "Georgia", max: 4, min: -5, stateID: "GA", final: -5},
{state: "Arizona", max: -1.5, min: -2, stateID: "AZ", final: -2}....]

【问题讨论】:

  • 排除此对象是什么意思?也许您想在对列表进行排序之前先执行filter。
  • 你不能“把任何东西排除在外”。您必须定义它在排序之后应该具有的位置,当然可以是“在其他一切之前”。
  • 您想将 first 对象排除在排序之外,还是要保留“U.S.”没有排序的对象,它恰好是这个特定示例数据集中的第一个对象?

标签: javascript arrays sorting ecmascript-6


【解决方案1】:

我相信你正在寻找

function setStatesOrder(stateOrderArr){
    return stateOrderArr.sort((x,y) => (y.state=="U.S.")-(x.state=="U.S.") || x.min - y.min);
}

如果它们应该以某种方式订购,你不能只是“不比较”两个项目。要么不要将它们放在一开始就排序的数组中,要么通过始终将具有.state == "U.S." 的项目视为比其他所有项目小来找到一个特殊对待它们的比较。

【讨论】:

  • @torazaburo 这基本上等同于您(现已删除)的答案,如果x 和y 都是U.S.,则返回0 的额外好处
  • 强制布尔运算是一个巧妙的技巧,但我认为它会严重损害可读性。
  • @Mic 不,实际上它很好地反映了比较函数的典型模式,即something(A) - something(B)。
  • 然而,对于后来了解它的普通维护程序员来说,其意图仍然不清楚。因为您有生成布尔值的表达式,然后您将其用于算术运算,然后出于布尔逻辑的目的再次将其视为布尔值。这在学术上很有趣,但是对于生产代码来说是一个坏习惯。对于这个问题的参数来说,这也是一个完全不必要的复杂化。
  • @Mic return y.state=="U.S."&&x.state!="U.S." ? 1 : x.state=="U.S."&&y.state!="U.S." -1 : x.min - y.min 也不是一个可读的替代方案……你很快就会习惯这个把戏。
【解决方案2】:

如果您不介意返回一个新数组而不是修改旧数组,那么(在我看来)不要弄乱.sort 函数并明确地从排序:

function setStatesOrder(stateOrderArr) {
  const [firstState, ...restOfStates] = stateOrderArr;
  restOfStates.sort((x,y) => x.min - y.min);
  return [firstState, ...restOfStates];

  //The previous two lines can also be combined, as
  //return [firstState, ...restOfStates.sort((x,y) => x.min - y.min)];
}

const stateOrderArr  = [
{state: "U.S.", max: 1, min: -14, stateID: "US", final: 0.3},
{state: "Ohio", max: 5, min: -2, stateID: "OH", final: 5},
{state: "Georgia", max: 4, min: -5, stateID: "GA", final: -5},
{state: "Arizona", max: -1.5, min: -2, stateID: "AZ", final: -2}];

console.log(setStatesOrder(stateOrderArr))

【讨论】:

    【解决方案3】:
    stateOrderArr.sort(
      (x,y) => x.state === "U.S". ? -1 : y.state === "U.S." ? +1 ? x.min - y.min);
    

    换句话说,说美国永远比什么都少。

    但是,首先排序,然后将 US 移到最前面可能更符合语义。这是将某些东西移到前面的小程序:

    function moveToFront(array, condition) {
      return array.splice(array.findIndex(condition), 1).concat(array);
    }
    

    这利用了Array.splice 返回已删除项目这一事实。

    然后

    moveToFront(
      array.sort((a, b) => a.min - b.min),
      a => a.state === "U.S.");
    

    【讨论】:

      【解决方案4】:

      在排序前过滤你的数组:

      function setStatesOrder(stateOrderArr){
         return stateOrderArr
           .filter(e => e.state !== "U.S.")
           .sort((x,y) => x.min - y.min);
      }
      
      
      stateOrderArr  = [
        {state: "U.S.", max: 1, min: -14, stateID: "US", final: 0.3},
        {state: "Ohio", max: 5, min: -2, stateID: "OH", final: 5},
        {state: "Georgia", max: 4, min: -5, stateID: "GA", final: -5},
        {state: "Arizona", max: -1.5, min: -2, stateID: "AZ", final: -2}]
      
      const ordered = setStatesOrder(stateOrderArr);
      ordered.forEach(e => console.log(e.state));
      
      Georgia
      Ohio
      Arizona
      

      你可以在这里运行它:https://runkit.com/arthur/5812319a2e7a3c0014799825

      【讨论】:

        【解决方案5】:

        排序谓词总是需要返回一个值。我认为这是一个使用三元运算符的好地方。形式为“[条件] ? [if true] : [if false]”

        function setStatesOrder(stateOrderArr){
        
          return stateOrderArr.sort((x,y) => x.state === "U.S." ? -1 : x.min - y.min);
        
        }
        
        var stateOrderArr  = [
        {state: "U.S.", max: 1, min: -14, stateID: "US", final: 0.3},
        {state: "Ohio", max: 5, min: -2, stateID: "OH", final: 5},
        {state: "Georgia", max: 4, min: -5, stateID: "GA", final: -5},
        {state: "Arizona", max: -1.5, min: -2, stateID: "AZ", final: -2}]
        
        document.write(setStatesOrder(stateOrderArr).map((x) => x.state));

        另一种有效的方法是删除您不想排序的元素,并在完成后将它们放回原处。对于一个元素,您可以使用 Array.prototype.shift 在排序之前取下第一个元素,然后使用 Array.prototype.unshift 将其放回原处。我认为您的情况没有可衡量的差异。

        function setStatesOrder(stateOrderArr){
          let first = stateOrderArr.shift();
          stateOrderArr = stateOrderArr.sort((x,y) => x.min - y.min);
          stateOrderArr.unshift(first);
          return stateOrderArr;
        
        }
        
        var stateOrderArr  = [
        {state: "U.S.", max: 1, min: -14, stateID: "US", final: 0.3},
        {state: "Ohio", max: 5, min: -2, stateID: "OH", final: 5},
        {state: "Georgia", max: 4, min: -5, stateID: "GA", final: -5},
        {state: "Arizona", max: -1.5, min: -2, stateID: "AZ", final: -2}]
        
        document.write(setStatesOrder(stateOrderArr).map((x) => x.state));

        【讨论】:

        • 你不能只在第一个参数是U.S. 时才返回-1。如果它在y 中怎么办?如果谓词两者都匹配怎么办?
        • 根据问题,它位于第一位。我不仅可以做到,而且我已经做到了,而且它按预期工作。
        • 比较函数不应该返回所需的索引,只是两个项目是否更大,等于或小于彼此。看看over here关于错误但在极端情况下工作的比较函数(当然,在示例中,如果只比较min值,美国将始终首先排序)
        • 你错了。你坚持认为这里有问题,但没有。只要 US 是数组中的第一个元素 - 问题表明它是 - 除非它移动,否则它永远不会是 y ,这是 -1 阻止的。它永远不会被排除在第一个位置之外,这是询问。
        • 假设美国永远排在第一位也是不合理的,即使在示例数据集中恰好是这种情况。
        猜你喜欢
        • 2021-06-11
        • 1970-01-01
        • 2016-10-02
        • 1970-01-01
        • 1970-01-01
        • 2021-02-23
        • 2018-11-01
        • 1970-01-01
        相关资源
        最近更新 更多