动态表达中的代码味道

发布于 2024-10-11 23:26:01 字数 2301 浏览 2 评论 0原文

此代码解决了 http://www.programgood.net/2011 中概述的一个有趣的难题/01/13/DynamicOperatorsGuernseyChallenge.aspx

问题: 这里似乎有很多重复。这里浮现出 DRY(不要重复自己)原则。有人看到重构吗?

        string opZ = "";
        string opA = "";
        string opB = "";
        string opC = "";
        string opD = "";
        for (int h = 1; h <= 2; h++) // making the first number positive or negative
        {
            if (h == 1) opZ = "";
            if (h == 2) opZ = "-";

            for (int i = 1; i <= 4; i++)
            {
                if (i == 1) opA = "*";
                if (i == 2) opA = "/";
                if (i == 3) opA = "+";
                if (i == 4) opA = "-";
                for (int j = 1; j <= 4; j++)
                {
                    if (j == 1) opB = "*";
                    if (j == 2) opB = "/";
                    if (j == 3) opB = "+";
                    if (j == 4) opB = "-";
                    for (int k = 1; k <= 4; k++)
                    {
                        if (k == 1) opC = "*";
                        if (k == 2) opC = "/";
                        if (k == 3) opC = "+";
                        if (k == 4) opC = "-";
                        for (int l = 1; l <= 4; l++)
                        {
                            if (l == 1) opD = "*";
                            if (l == 2) opD = "/";
                            if (l == 3) opD = "+";
                            if (l == 4) opD = "-";
                            string expression = opZ + 1 + opA + 3 + opB + 5 + opC + 7 + opD + 9;
                            DataTable dummy = new DataTable();
                            double result = Convert.ToDouble(dummy.Compute(expression, string.Empty));
                            if (result == 3)
                                Debug.WriteLine(expression + " = 3");

                            if (result == 47)
                                Debug.WriteLine(expression + " = 47");

                            if (result == 18)
                                Debug.WriteLine(expression + " = 18");

                        }
                    }
                }
            }
        }

This code solves an interesting puzzle outlined in http://www.programgood.net/2011/01/13/DynamicOperatorsGuernseyChallenge.aspx

Problem: There seems to be lots of repeating here.. DRY (Don't Repeat Yourself) principle springs to mind here. Anyone see a refactor?

        string opZ = "";
        string opA = "";
        string opB = "";
        string opC = "";
        string opD = "";
        for (int h = 1; h <= 2; h++) // making the first number positive or negative
        {
            if (h == 1) opZ = "";
            if (h == 2) opZ = "-";

            for (int i = 1; i <= 4; i++)
            {
                if (i == 1) opA = "*";
                if (i == 2) opA = "/";
                if (i == 3) opA = "+";
                if (i == 4) opA = "-";
                for (int j = 1; j <= 4; j++)
                {
                    if (j == 1) opB = "*";
                    if (j == 2) opB = "/";
                    if (j == 3) opB = "+";
                    if (j == 4) opB = "-";
                    for (int k = 1; k <= 4; k++)
                    {
                        if (k == 1) opC = "*";
                        if (k == 2) opC = "/";
                        if (k == 3) opC = "+";
                        if (k == 4) opC = "-";
                        for (int l = 1; l <= 4; l++)
                        {
                            if (l == 1) opD = "*";
                            if (l == 2) opD = "/";
                            if (l == 3) opD = "+";
                            if (l == 4) opD = "-";
                            string expression = opZ + 1 + opA + 3 + opB + 5 + opC + 7 + opD + 9;
                            DataTable dummy = new DataTable();
                            double result = Convert.ToDouble(dummy.Compute(expression, string.Empty));
                            if (result == 3)
                                Debug.WriteLine(expression + " = 3");

                            if (result == 47)
                                Debug.WriteLine(expression + " = 47");

                            if (result == 18)
                                Debug.WriteLine(expression + " = 18");

                        }
                    }
                }
            }
        }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

两人的回忆 2024-10-18 23:26:01

好吧,第一个明显的重构是拥有一个运算符数组:

String[] operators = { null, "*", "/", "+", "-" };

然后使用:(

opC = operators[j]; // etc

我个人会使用从 0 到 3 而不是 1 到 4 的循环 - 这在我看来更惯用,但那是另一回事。

)构建排列的方式。我实际上会使用 LINQ 来实现此目的:

string[] prefixes = { "", "-" };
string[] operators = { "*", "/", "+", "-" };
var expressions = from prefix in prefixes
                  from opA in operators
                  from opB in operators
                  from opC in operators
                  from opD in operators
                  select prefix + 1 + opA + 3 + opB + 5 + opC + 7 + opD + 9;

foreach (string expression in expressions)
{
    ...
}

Well, the first obvious refactoring would be to have an array of operators:

String[] operators = { null, "*", "/", "+", "-" };

Then use:

opC = operators[j]; // etc

(Personally I'd use loops going from 0 to 3 instead of 1 to 4 - that's more idiomatic IMO, but that's a different matter.)

Then there's the way of building the permutations. I'd actually use LINQ for this:

string[] prefixes = { "", "-" };
string[] operators = { "*", "/", "+", "-" };
var expressions = from prefix in prefixes
                  from opA in operators
                  from opB in operators
                  from opC in operators
                  from opD in operators
                  select prefix + 1 + opA + 3 + opB + 5 + opC + 7 + opD + 9;

foreach (string expression in expressions)
{
    ...
}
夏有森光若流苏 2024-10-18 23:26:01
char[] ops = new [] {'*','/','+','-'};
foreach(string opA in ops)
 foreach(string opB in ops)
  foreach(string opC in ops)
   foreach(string opD in ops)
    foreach(string opZ in new []{'-',' '}) {
     string expression = opZ + 1 + opA + 3 + opB + 5 + opC + 7 + opD + 9;
     DataTable dummy = new DataTable();
     double result = Convert.ToDouble(dummy.Compute(expression, string.Empty));
     if (result == 3)
       Debug.WriteLine(expression + " = 3");
     if (result == 47)
       Debug.WriteLine(expression + " = 47");
     if (result == 18)
      Debug.WriteLine(expression + " = 18");
    } 
char[] ops = new [] {'*','/','+','-'};
foreach(string opA in ops)
 foreach(string opB in ops)
  foreach(string opC in ops)
   foreach(string opD in ops)
    foreach(string opZ in new []{'-',' '}) {
     string expression = opZ + 1 + opA + 3 + opB + 5 + opC + 7 + opD + 9;
     DataTable dummy = new DataTable();
     double result = Convert.ToDouble(dummy.Compute(expression, string.Empty));
     if (result == 3)
       Debug.WriteLine(expression + " = 3");
     if (result == 47)
       Debug.WriteLine(expression + " = 47");
     if (result == 18)
      Debug.WriteLine(expression + " = 18");
    } 
苄①跕圉湢 2024-10-18 23:26:01

我想在使用 DataTable.Compute 时这样做没有任何意义,但

var calculator = new DataTable () ;
var operators  = "*/+-" ;
for (int i = 0 ; i < 0x200 ; ++i)
{
  var value = calculator.Compute (String.Format ("{0}1{1}3{2}5{3}7{4}9",
    (i & 0x100) != 0 ? "-" : "",
    operators[(i >> 0) & 3],
    operators[(i >> 2) & 3],
    operators[(i >> 4) & 3],
    operators[(i >> 6) & 3]), String.Empty) ;
  ...
}

否则,如果更深奥的话,这肯定会更快:

var opstrings = "+-*/" ;
var operators = new Func<int, int, int>[] {
  (a, b) => a + b,
  (a, b) => a - b,
  (a, b) => a * b,
  (a, b) => a / b, } ;
for (int i = 0 ; i < 0x200 ; ++i)
{
  var stack = 0 ; // seed value
  var last  = 0 ; // imitate + for lowest precedence
  var value =(i & 0x100) != 0 ? -1 : 1 ;

  for (int j = 0 ; j < 5 ; ++j)    // extra item to force last reduction
  {
    var oper  = (i >> j * 2) & 3 ; // "input" operator
    var input =  3  + j * 2 ;      // "input" number
    if (oper / 2 <= last / 2)      // reduce below top?
    {
      stack = operators[last] (stack, value) ;
      last  = oper  ;              // shift operator
      value = input ;              // shift number
    }
    else                           // reduce top
      value = operators[oper] (value, input) ;
  }

  var result  = stack ;
  if (result == 3 || result == 47 || result == 18)
    Debug.WriteLine ("{0}1{1}3{2}5{3}7{4}9 = {5}",
      (i & 0x100) != 0 ? "-" : "",
      opstrings[(i >> 0) & 3],
      opstrings[(i >> 2) & 3],
      opstrings[(i >> 4) & 3],
      opstrings[(i >> 6) & 3],
      result) ;
}

I suppose there's no real point doing this while using DataTable.Compute, but

var calculator = new DataTable () ;
var operators  = "*/+-" ;
for (int i = 0 ; i < 0x200 ; ++i)
{
  var value = calculator.Compute (String.Format ("{0}1{1}3{2}5{3}7{4}9",
    (i & 0x100) != 0 ? "-" : "",
    operators[(i >> 0) & 3],
    operators[(i >> 2) & 3],
    operators[(i >> 4) & 3],
    operators[(i >> 6) & 3]), String.Empty) ;
  ...
}

Otherwise, this will definitely be faster if somewhat more abstruse:

var opstrings = "+-*/" ;
var operators = new Func<int, int, int>[] {
  (a, b) => a + b,
  (a, b) => a - b,
  (a, b) => a * b,
  (a, b) => a / b, } ;
for (int i = 0 ; i < 0x200 ; ++i)
{
  var stack = 0 ; // seed value
  var last  = 0 ; // imitate + for lowest precedence
  var value =(i & 0x100) != 0 ? -1 : 1 ;

  for (int j = 0 ; j < 5 ; ++j)    // extra item to force last reduction
  {
    var oper  = (i >> j * 2) & 3 ; // "input" operator
    var input =  3  + j * 2 ;      // "input" number
    if (oper / 2 <= last / 2)      // reduce below top?
    {
      stack = operators[last] (stack, value) ;
      last  = oper  ;              // shift operator
      value = input ;              // shift number
    }
    else                           // reduce top
      value = operators[oper] (value, input) ;
  }

  var result  = stack ;
  if (result == 3 || result == 47 || result == 18)
    Debug.WriteLine ("{0}1{1}3{2}5{3}7{4}9 = {5}",
      (i & 0x100) != 0 ? "-" : "",
      opstrings[(i >> 0) & 3],
      opstrings[(i >> 2) & 3],
      opstrings[(i >> 4) & 3],
      opstrings[(i >> 6) & 3],
      result) ;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文