Shortening a Javascript if-else structure

前端 未结 7 821
情书的邮戳
情书的邮戳 2021-02-13 00:05

The code I have is:

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


        
相关标签:
7条回答
  • 2021-02-13 00:10

    I'd recommend to avoid multiple calls to 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;
    }
    

    Also I've nested the if-else-statements in a (hopefully) more meaningful structure - that depends on your usecase though. Might be more helpful if you returned values like -2, -1, 1 and 2 instead or something. A ternary operator could save you some writing, but it's not necessarily getting clearer.

    Alternatively, some maths could help you:

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

    Though it leads to 3 instead of 4 in case value(d) === median-stdev. See @6502's answer on how to avoid that.

    0 讨论(0)
  • 2021-02-13 00:11

    You can calculate the difference between the value and the median, which makes the comparisons simpler:

    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;
      }
    };
    

    You can also write it using the conditional operator instead of if statements:

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

    Whether this is nicer or not is a matter of taste, but it's shorter.

    0 讨论(0)
  • 2021-02-13 00:16

    Of course calling value(d) multiple times is something you can avoid.

    Also you can shorten a little using the symmetry:

      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));
      };
    

    Probably not a good idea for a real project however... I didn't test but I wouldn't be surprised to find this code slower than the original in your question and for sure I find it harder to maintain.

    Note that excluding one-shot throwaway scripts normally code is written once and read many times (for maintenance like improvements or debugging), thus "easier to read" is normally much more important than "easier to write".

    When shorter means "easier to read" is a good thing, when it starts meaning "harder to read" it's not.

    0 讨论(0)
  • 2021-02-13 00:23

    "nicer" way? No, not really.

    Alternate way(s) - yes, plentiful.

    One possibility is storing the condition and result in an array

    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}
    ];
    

    Then just enumerating that list as part of the function

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

    A bit easy to extend than your original, but by [diety] its ugly as sin!

    0 讨论(0)
  • 2021-02-13 00:29

    To complete the set, here is the switch way referenced by @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;
      }
    };
    
    0 讨论(0)
  • 2021-02-13 00:33

    I don't see much room for improvements which could guarantee the same readability of the starting case. If you are really returning integers, and they aren't there just for the sake of this example, I would suggest you to return something more meaningful.

    You could for sure compute value(d) just once

    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;
      }
    };
    

    Also, you might want to avoid multiple returns, or maybe you don't, for me they're the same, each has advanges/disadvantages:

    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;
    };
    

    If you assign a meaningful name to code you are giving even more information to the guy who is reading your code.

    0 讨论(0)
提交回复
热议问题