使嵌套if-else更易于管理和有效

时间:2018-04-23 05:38:28

标签: c++

我正在开发一个分析和预测波形模式的项目,但问题是嵌套if / else的代码变得越来越难以管理,这里是片段:

for (int x = 1; x <= 24; x++)            
{
if ((15 <= Angles[x]) && (Angles[x] <= 30))
  {
   if(x<=6)
    {
      counter=counter+4;
      if (edges[x] < edges[x+2]) { counter = counter - 4; }
      else{counter=counter+5; };
      if (Angles[x] < Angles[x + 2]) { counter = counter - 6; }
      else{counter=counter + 4; };
      if ((edges[x+1] - edges[x]) < (edges[x + 3] - edges[x + 2])) { counter= counter - 6; }
      else{counter-counter + 5; };
      if (gradient[x] < gradient[x + 2]) { counter = counter - 6; }
      else{counter=counter + 5; };
    };

if((7<=x)&&(x<=12))
{
  counter = counter - 10;
  if (edges[x] < edges[x+2]) { counter = counter - 5; }
  else{counter=counter + 6; };
  if (Angles[x] < Angles[x + 2]) { counter = counter - 7; }
  else{counter=counter + 6; };
  if ((edges[x+1] - edges[x]) < (edges[x + 3] - edges[x + 2])) { counter = 
  counter - 6; }
  else{counter-counte+7; };
  if (gradient[x] < gradient[x + 2]) { counter = counter - 6; }
  else{counter=counter+8; };
};

if((13<=x)&&(x<=18))
{
  counter = counter - 30;
   if (edges[x] < edges[x+2]) { counter = counter - 7; }
   else{counter=counter + 6; };
   if (Angles[x] < Angles[x + 2]) { counter = counter - 7; }
   else{counter=counter + 5; };
   if ((edges[x+1] - edges[x]) < (edges[x + 3] - edges[x + 2])) { counter = 
   counter - 7; }
   else{counter-counter+5; };
   if (gradient[x] < gradient[x + 2]) { counter = counter + 5; }
   else{counter=counter + 5; };
};

//there are more waves classification and weightage to come//
if ((30 <= Angles[x]) && (Angles[x] <= 45)){}.....
if ((45 <= Angles[x]) && (Angles[x] <= 60)){}.....
if(60 < Angles[x]){}....

};  
  

角度是存储波角值的容器。           边缘是波峰和波谷。           gradient包含wave的渐变值           counter是当前模式的权重。           值以串行方式存储在向量中。

这只是一个粗略的剥离片段(如果找到,则忽略语法错误)。 每个模式都包含一个for循环,其中包含嵌套的if / else。 还有13种模式。

我已经越过了5000行,只是写了if / else for循环。你能帮助我让这个更容易管理吗?

4 个答案:

答案 0 :(得分:3)

而不是

   if(x<=6)
    {
      counter=counter+4;
      if (edges[x] < edges[x+2]) { counter = counter - 4; }
      else{counter=counter+5; };
      if (Angles[x] < Angles[x + 2]) { counter = counter - 6; }
      else{counter=counter + 4; };
      if ((edges[x+1] - edges[x]) < (edges[x + 3] - edges[x + 2])) { counter= counter - 6; }
      else{counter-counter + 5; };
      if (gradient[x] < gradient[x + 2]) { counter = counter - 6; }
      else{counter=counter + 5; };
    };
你可以写

   if(x<=6)
    {
      counter = counter
        + 4
        + ((edges[x] < edges[x+2]) ? -4 : 5)
        + ((Angles[x] < Angles[x + 2]) ? -6 : 4)
        + (((edges[x+1] - edges[x]) < (edges[x + 3] - edges[x + 2])) ? -6 : 5)
        + ((gradient[x] < gradient[x + 2]) ? -6 : 5)
    };

如果您可以将条件放在自己的功能中,代码也会变得更加清晰。

我看到很多条件,比如array [x]&lt;阵列[X + 2]。您可以定义lambdas,如

auto raisingEdge = [&](int x) { return edges[x] < edges[x+2]; };

并像

一样使用它
counter += raisingEdge(x) ? -4 : 5;

这可以使您的代码更具可读性:

  if(x<=6)
    {
      counter = counter
        + 4
        + (raisingEdge(x) ? -4 : 5)
        + (raisingAngle(x) ? -6 : 4)
        + (raisingEdgeDelta(x) ? -6 : 5)
        + (raisingGradient(x) ? -6 : 5)
    };

(这些名字只是为了展示这个概念;我不知道也不关心这些价值究竟是什么)

答案 1 :(得分:2)

您还可以将lambdastencil push语义结合使用。

对于你的第一对if语句你可以做这样的事情:

condition ? if : else

您的其他auto comp = [&counter](int n, int m, int val1, int val2) { return n < m ? counter + val1 : counter + val2; }; counter = comp(edges[x], edges[x + 2], -4, 5); counter = comp(Angles[x], Angles[x + 2], -6, 4); 也是如此,您可以添加它们。

答案 2 :(得分:2)

我不确定你的if ... else if的小序列是无法管理的还是低效的(恕我直言,它是可管理和有效的,但需要更好的缩进;请考虑使用类似的工具重新格式化代码https://github.com/phpDocumentor/phpDocumentor2/issues/1834)。

除了astyle和兼容(例如GCC)编译器的其他答案之外,您可能考虑使用某些Clang

  • switch使用language extension(这是我的偏好,并且非常易读),所以像

    switch(x) { 
       case 1 ... 6:
        {
          counter=counter+4;
          if (edges[x] < edges[x+2]) { counter = counter - 4; }
          else {counter=counter+5; };
          if (Angles[x] < Angles[x + 2]) { counter = counter - 6; }
          else{counter=counter + 4; };
          if ((edges[x+1] - edges[x]) < (edges[x + 3] - edges[x + 2])) 
            { counter= counter - 6; }
          else{counter-counter + 5; };
          if (gradient[x] < gradient[x + 2]) { counter = counter - 6; }
          else{counter=counter + 5; };
       };
       break;
    
  • 使用case ranges

  • 计算出的goto

当然,您需要(有意识地)决定使用C ++ 11(请参阅labels as values)或C ++ 14标准未定义的语言扩展。 (上面的代码甚至无法在某些Microsoft编译器上编译,因为它是非标准的。)

如果使用n3337和/或GCC,请不要忘记启用所有警告和调试信息,例如Clang -Wall -Wextra -gg++clang++

  

我已经越过了5000行,只是写了if / else for循环。

您可以通过定义小的特定内部函数(可能是static个函数或私有成员函数)来决定to pass您的代码来处理每个案例。根据经验,尽量避免数千行的大量手写功能:定义每个最多几百行的较小内部函数,并适当地调用它们 - 也许只需要一次。即使只调用一次内部函数,在函数中放置几百行的块也常常(但并不总是)有用。由你明智地组织,并为你的内部职能提供有意义的名称。

C ++中的编码也是(许多)惯例和习惯的问题。我建议你研究一些refactor类似的(源于目标,精神上)的源代码,以获得灵感。 (您将在free softwaregithub和其他地方使用C ++找到许多自由软件项目。

sourceforge中,您甚至可以考虑从其他内容生成您的C ++代码(更高级别,特定于您的方法)。哟可能想要在其中生成some cases。也许这种#line directives方法在你的情况下是值得的(在尝试之前一定要阅读metaprogramming)。

答案 3 :(得分:1)

除了数字之外,每个块(以counter = counter - 10; 行开头)似乎相同。在这种情况下,我肯定会选择功能。数字将成为其参数。如果使它成为同一个类的方法,并且块中使用的变量是类属性,则新方法可以轻松访问它们。

这肯定有助于代码的可管理性。如果您在计算中发现错误,则只需更正一个位置。

经验法则:如果您不止一次地复制粘贴代码的某些部分,您应该考虑使其成为可以重复使用的实体,如宏,函数或类。

另请参阅:Wikipedia – Don't repeat yourself

顺便说一下,

counter -= 10;

(以及所有类似案例)可以缩短为

NameError                                 Traceback (most recent call last)
<ipython-input-26-d21b1cb0fcab> in <module>()
     19 download('http://data.mxnet.io/data/caltech-256/caltech-256-60-train.rec')
     20 
---> 21 upload_to_s3('train', 'caltech-256-60-train.rec')

<ipython-input-26-d21b1cb0fcab> in upload_to_s3(channel, file)
     13     data = open(file, "rb")
     14     key = channel + '/' + file
---> 15     s3.Bucket(bucket).put_object(Key=key, Body=data)
     16 
     17 

NameError: name 'bucket' is not defined