动态表达中的代码嗅觉

时间:2011-01-13 10:32:17

标签: c# refactoring

此代码解决了http://www.programgood.net/2011/01/13/DynamicOperatorsGuernseyChallenge.aspx

中概述的有趣谜题

问题:这里似乎有很多重复。干(不要重复自己)原则让人想到这里。有人看到重构吗?

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

                        }
                    }
                }
            }
        }

3 个答案:

答案 0 :(得分:3)

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

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

然后使用:

opC = operators[j]; // etc

(我个人使用的循环从0到3而不是1到4 - 这是更惯用的IMO,但这是另一回事。)

然后就是建立排列的方法。我实际上使用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)
{
    ...
}

答案 1 :(得分:1)

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

答案 2 :(得分:0)

我认为在使用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) ;
}