Подтвердить что ты не робот

Сокращение структуры Javascript if-else

Код, который у меня есть:

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

Есть ли лучший способ сделать это?

4b9b3361

Ответ 1

Конечно, вызов value(d) несколько раз - это то, чего вы можете избежать.

Также вы можете немного сократить 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));
  };

Вероятно, это не очень хорошая идея для реального проекта... Я не тестировал, но не удивился бы, если бы этот код был медленнее оригинала в вашем вопросе, и, конечно же, мне было тяжелее его поддерживать.

Обратите внимание, что исключая одноразовые сценарии выброса, обычно код записывается один раз и читается много раз (для обслуживания, например, улучшения или отладки), поэтому "легче читать" обычно гораздо важнее, чем "проще писать".

Когда более короткое означает "легче читать", это хорошо, когда оно начинает означать "труднее читать", это не так.

Ответ 2

Чтобы завершить набор, вот путь 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;
  }
};

Ответ 3

Это решение более приятное, но я бы не рекомендовал его использовать в производстве, поскольку это путается:

4 - [median + stdev, median, median - stdev].filter(function(e, i, a) {
    return value(d) > e;
}).length 

Ответ 4

Вы можете рассчитать разницу между значением и средой, что упрощает сравнение:

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

Хорошо ли это или нет, это вопрос вкуса, но он короче.

Ответ 5

"лучше"? Нет, не совсем.

Альтернативный способ - да, обильный.

Одна возможность - сохранить условие и привести к массиву

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] его уродливым, как грех!

Ответ 6

Я не вижу много возможностей для улучшений, которые могли бы гарантировать такую ​​же читаемость исходного кода. Если вы действительно возвращаете целые числа, и их нет только ради этого примера, я бы предложил вам вернуть что-то более содержательное.

Вы можете точно вычислить 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, вы даете еще больше информации тому парню, который читает ваш код.

Ответ 7

Я бы рекомендовал избежать нескольких вызовов 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 в (надеюсь) более значимую структуру, которая, однако, зависит от вашего usecase. Может быть полезно, если вы вернете значения, например -2, -1, 1 и 2, или что-то еще. Тройной оператор мог бы сэкономить вам несколько писем, но это не обязательно стало понятным.

В качестве альтернативы, некоторые математики могут вам помочь:

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

Хотя это приводит к 3 вместо 4 в случае value(d) === median-stdev. См. Ответ @6502 о том, как этого избежать.

Ответ 8

Хорошо, если мы собираемся сделать короткие, творческие решения...

var level = function(d){
    d = value(d);
    return +(d<=median+stdev)+ +(d<=median)+ +(d<=median-stdev) + 1
}

Ответ 10

Это не удаляет структуру 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) только один раз.

Ответ 11

Другой вариант -— игнорируя полезность математики в этом случае; заключается в том, чтобы вообще отказаться от утверждений 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
  ;
}

Ответ 12

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 может быть извлечен из области действия, если это необходимо.

Ответ 13

Я бы не коснулся кода.

Здесь есть много опубликованных кодов, но все же ваш самый читаемый.

Ответ 14

Попробуйте это...

  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)