17

我的代码是:

 var level = function (d) {
    if (value(d) > median + stdev) {
        return 1;
    } else if (value(d) > median) {
        return 2;
    } else if (value(d) > median - stdev) {
        return 3;
    } else {
        return 4;
    }
 };

有没有更好的方法来做到这一点?

4

14 回答 14

15

当然value(d),您可以避免多次调用。

您也可以使用对称性缩短一点:

  var level = function (d) {
    //
    //               -std    median  +std
    // ----------------|-------|-------|------------------
    // 4444444444444444 3333333 2222222 111111111111111111
    //
    var i = Math.floor((median - value(d)) / stddev) + 3;
    return Math.max(1, Math.min(4, i));
  };

然而,对于一个真正的项目来说可能不是一个好主意......我没有测试,但我不会惊讶地发现这段代码比你的问题中的原始代码慢,而且我肯定发现它更难维护。

请注意,不包括一次性一次性脚本,通常代码编写一次并读取多次(用于改进或调试等维护),因此“易于阅读”通常比“易于编写”重要得多。

当更短意味着“更容易阅读”是一件好事,当它开始意味着“更难阅读”时,它就不是了。

于 2013-07-16T14:43:36.387 回答
7

要完成设置,这是switch@austin 引用的方式:

var level = function (d) {
  var d = value(d) - median;
  switch (true) {
  case d > stdev : return 1;
  case d > 0:      return 2;
  case d > -stdev: return 3;
  default:         return 4;
  }
};
于 2013-07-16T14:53:14.143 回答
4

这个解决方案更好,但我不建议在生产中使用它,因为它有点令人困惑:

4 - [median + stdev, median, median - stdev].filter(function(e, i, a) {
    return value(d) > e;
}).length 
于 2013-07-16T14:38:18.623 回答
3

您可以计算该值与中位数之间的差值,从而使比较更简单:

function level(d) {
  var n = value(d) - median;
  if (n > stdev) {
    return 1;
  } else if (n > 0) {
    return 2;
  } else if (n > -stdev) {
    return 3;
  } else {
    return 4;
  }
};

您也可以使用条件运算符而不是if语句来编写它:

function level(d) {
  var n = value(d) - median;
  return n > stdev ? 1 :
    n > 0 ? 2 :
    n > -stdev ? 3 :
    4;
  }
};

这是否更好是一个品味问题,但它更短。

于 2013-07-16T14:40:12.160 回答
2

“更好”的方式?不,不是。

替代方式 - 是的,很多。

一种可能性是将条件和结果存储在数组中

var levelFunctions = [
  { func: function(d){ return value(d) > median + stdev; }, val:1},
  { func: function(d){ return value(d) > median ; }, val:2},
  { func: function(d){ return value(d) > median - stdev; }, val:3},
  { func: function(d){ return true; }, val:4}
];

然后只是将该列表枚举为函数的一部分

var level = function (d) {
    for(var i=0;i<levelFunctions.length;i++){
       if(levelFunctions[i].func(d))
           return levelFunctions[i].val;
    }
 };

比你原来的更容易扩展,但是通过[diety]它丑得像罪!

于 2013-07-16T14:37:27.123 回答
2

我认为改进的空间不大,可以保证与起始案例相同的可读性。如果您真的要返回整数,并且它们不只是为了这个例子,我建议您返回更有意义的东西。

你肯定可以只计算value(d)一次

var level = function (d) {
  var dValue = value(d);
  if (dValue > median + stdev) {
    return 1;
  } else if (dValue > median) {
    return 2;
  } else if (dValue > median - stdev) {
    return 3;
  } else {
   return 4;
  }
};

此外,您可能希望避免多次退货,或者您可能不想,对我来说它们是相同的,每个都有优点/缺点:

var level = function (d) {
  var dValue = value(d),
      code = 4;
  if (dValue > median + stdev) {
    code = 1;
  } else if (dValue > median) {
    code = 2;
  } else if (dValue > median - stdev) {
    code = 3;
  } 
  return code;
};

如果您为您指定一个有意义的名称,code那么您正在向正在阅读您的代码的人提供更多信息。

于 2013-07-16T14:38:18.840 回答
2

我建议避免多次调用value

function level(d) {
    var diff = value(d) - median;
    if (diff > 0) {
        if (diff > stdev)
            return 1;
        else
            return 2;
    else
        if (diff > -stdev)
            return 3;
        else
            return 4;
}

此外,我将 if-else-statements 嵌套在(希望)更有意义的结构中 - 不过这取决于您的用例。-2如果您返回诸如,和之类的值-1,可能会更有帮助。三元运算符可以为您节省一些写作时间,但不一定会变得更清晰。12

或者,一些数学可以帮助你:

function level(d) {
    var diff = value(d) - median;
    return 2 + (diff > 0 ? -.5 : .5) * (Math.abs(diff) > stdev ? 3 : 1);
}

虽然它导致3而不是4in case value(d) === median-stdev。有关如何避免这种情况,请参阅@6502 的回答。

于 2013-07-16T14:38:58.840 回答
2

好吧,如果我们要寻求简短的创造性解决方案...

var level = function(d){
    d = value(d);
    return +(d<=median+stdev)+ +(d<=median)+ +(d<=median-stdev) + 1
}
于 2013-07-17T02:10:37.637 回答
1

您可以使用switch声明(Mozilla Developer Network docs)。

编辑:如果您认为在 switch 语句中不可能做范围,这里有一个类似问题的答案

于 2013-07-16T14:29:20.947 回答
1

这不会删除 if/else 结构,但会使代码更简洁:

var level = function (d) {
    var delta = value(d) - median;
    if (delta > stdev) {
        return 1;
    } else if (delta > 0) {
        return 2;
    } else if (delta > -stdev) {
        return 3;
    } else {
        return 4;
    }
 };

value(d)它具有只调用一次的额外好处。

于 2013-07-16T14:38:25.577 回答
1

另一种选择——在这种情况下忽略数学的用处——是完全取消 if 语句。与使用三元运算符的方法相比,我通常更喜欢这种方法。我倾向于认为这比拥有多个 if/else 结构(对于简单的情况)更具可读性,但这只是因为我精通 JavaScript 逻辑运算符的方式。1 && 3 === TRUE我完全可以理解对于那些正在学习的人,或者那些用陌生语言和外语编码的人来说,这看起来有多么奇怪。3

var level = function (d) {
  d = value(d);
  return ((d > median + stdev) && 1) 
      || ((d > median)         && 2) 
      || ((d > median - stdev) && 3)
      || 4
  ;
}

另一个可能的优化——这个问题独有的——是median从比较中删除,但是,这很可能会影响可读性:

var level = function (d) {
  d = value(d) - median;
  return ((d > + stdev) && 1) 
      || ((d > 0)       && 2) 
      || ((d > - stdev) && 3)
      || 4
  ;
}
于 2013-07-16T19:41:06.567 回答
1
var level = function(d){
    var n = value(d) - median, values = [];
    values[stdev]  = 1;
    values[0]      = 2;
    values[-stdev] = 3;
    return values[n] ? values[n] : 4;
};

values如果需要,可以将其拉出函数范围。

于 2013-07-18T20:26:22.487 回答
1

我不会碰代码。

这里有很多张贴的代码,但你的代码仍然是最易读的。

于 2013-07-20T11:47:12.973 回答
0

试试这个...

  var reduceCalcVal=value(d);   //reduce repeated calculation
  var cheats=new Array( reduceCalcVal > median + stdev
    ,reduceCalcVal  > median, reduceCalcVal > median - stdev);
    n=(cheats.indexOf(true)==-1)?4:cheats.indexOf(true)+1;
    alert(n)
于 2013-07-16T14:53:45.127 回答