Linq算术运算符组合

时间:2009-10-18 09:27:46

标签: c# linq linq-to-objects math combinations

在尝试解决以下任务时:

使用算术运算符(+, - ,*,/)重新排列四个五等于数字1到10。

   实施例:5/5 + 5-5 = 1,5 / 5 + 5/5 = 2

我在没有使用Linq的情况下尝试使用C#(我不知道如何继续进行)

public void GetDetails()
{

   char[] sym = new char[] { '+', '-', '/', '*' };

   int[] AOf5 = new int[] { 5, 5, 5, 5 };


for (int i = 0; i <4; i++)
 {
    for (int j = 0; j <4; j++)
     {
       for (int k = 0; k <4; k++)
          {
             for (int l = 0; l < 4; l++)
              {

                int result1 = AOf5[0] + sym[i] + AOf5[1] + sym[j] +
                AOf5[2] + sym[k] + AOf5[3];

               int result2 = AOf5[0] + sym[i] + AOf5[1] + sym[j] +
               AOf5[2] + sym[l] + AOf5[3];

              int result3 = AOf5[0] + sym[i] + AOf5[1] +
              sym[k] + AOf5[2] + sym[l] + AOf5[3];
              ....
              ....

              }  

         }

      }
  }

}

如果没有linq并使用linq,我无法完成它。期待你的帮助。

5 个答案:

答案 0 :(得分:4)

从左到右(没有优先权)应用,我可以得到:

1: ((5+5)-5)/5
2:
3: ((5+5)+5)/5
4: ((5*5)-5)/5
5: ((5-5)*5)+5
6: ((5*5)+5)/5
7: ((5+5)/5)+5
8:
9:
10: ((5+5)+5)-5

使用(编辑:oops - 不需要“没有div”的东西):

    var operators = new[] {
          new { Name = "+", Func = (Func<decimal,decimal,decimal>)((x,y)=>x+y) },
          new { Name = "-", Func = (Func<decimal,decimal,decimal>)((x,y)=>x-y) },
          new { Name = "/", Func = (Func<decimal,decimal,decimal>)((x,y)=>x/y) },
          new { Name = "*", Func = (Func<decimal,decimal,decimal>)((x,y)=>x*y) }
      };
    var options = from i in Enumerable.Range(1, 10)
                  select new {i, op=(
                    from op1 in operators
                    let v1 = op1.Func(5,5)
                    from op2 in operators
                    let v2 = op2.Func(v1, 5)
                    from op3 in operators
                    let v3 = op3.Func(v2,5)
                    where v3 == i
                    select "((5" + op1.Name + "5)" + op2.Name + "5)"
                       + op3.Name + "5").FirstOrDefault()};
    foreach (var opt in options)
    {
        Console.WriteLine(opt.i + ": " + opt.op);
    }

答案 1 :(得分:2)

我是以原始方式做到的,我不确定答案是否正确。但是在电子表格中更容易完成。基本上我修改了linqfying的代码来生成代码。

就是这样:

public static void GetDetails()
{
    int ctr = 0;
    char[] sym = new char[] { '+', '-', '/', '*' };
    string num = "5";
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            for (int k = 0; k < 4; k++)
            {
                for (int l = 0; l < 4; l++)
                {
                    ctr++;
                    string str = num + sym[i] + num + sym[j] + num + sym[k] + num;
                    Console.WriteLine("res = " + str + "; ");
                    Console.WriteLine("if(res>=1 && res<=10)");
                    Console.WriteLine("Console.WriteLine(\"" + str + "\");");
                }

            }

        }
    }
    //Console.WriteLine("Total:" + ctr.ToString());
}

它生成256组操作,我将其输出到文本文件,复制并粘贴到新方法中:

public static void runit()
{
    float res = 0;
    res = 5+5+5+5;
    if (res >= 1 && res <= 10)
        Console.WriteLine("5+5+5+5");
    res = 5+5+5+5;
    if (res >= 1 && res <= 10)
        Console.WriteLine("5+5+5+5");
    res = 5+5+5+5;
    if (res >= 1 && res <= 10)
        Console.WriteLine("5+5+5+5");
    //......
    //......
    //......
    //......
    res = 5*5*5*5;
    if (res >= 1 && res <= 10)
        Console.WriteLine("5*5*5*5");

}

再次运行它,我得到76个非unqiue操作,适合1到10之间。 这里有19个独特的(仅从左到右操作):

5*5/5/5
5*5/5+5
5/5*5/5
5/5*5+5
5/5/5+5
5/5+5/5
5/5+5-5
5/5-5+5
5+5*5/5
5+5/5*5
5+5/5/5
5+5/5-5
5+5+5-5
5+5-5/5
5+5-5+5
5-5/5/5
5-5/5+5
5-5+5/5
5-5+5+5

我确信有人可以提出更有创意的事情:P

添加:

我在与Marc的答案匹配后意识到,初始循环并没有涵盖所有的排列,我的答案是不对的。但既然我已经花了很长时间,我会让它留下来。 :P

答案 2 :(得分:2)

Marc解决方案中唯一缺失的案例是具有操作优先级的案例,例如:5/5 + 5/5。我将它们添加到一个联合中,这是正确的查询 Marc,如果您使用下面的代码更新您的答案(如果您认为这是正确的),我将删除此答案:

var operators = new[] {
              new { Name = "+", Func = (Func<decimal,decimal,decimal>)((x,y)=>x+y) },
              new { Name = "-", Func = (Func<decimal,decimal,decimal>)((x,y)=>x-y) },
              new { Name = "/", Func = (Func<decimal,decimal,decimal>)((x,y)=>x/y) },
              new { Name = "*", Func = (Func<decimal,decimal,decimal>)((x,y)=>x*y) }
          };

var options = from i in Enumerable.Range(1, 10)
              select new
              {
                  i,
                  op = (
                      from op1 in operators
                      let v1 = op1.Func(5, 5)
                      from op2 in operators
                      let v2 = op2.Func(v1, 5)
                      from op3 in operators
                      let v3 = op3.Func(v2, 5)
                      where v3 == i
                      select "((5" + op1.Name + "5)" + op2.Name + "5)"
                         + op3.Name + "5")
                      .Union(
             //calculate 2 operations (the left and the right one),  
             //then operate them together.
                        from op1 in operators
                        let v1 = op1.Func(5, 5)
                        from op2 in operators
                        let v2 = op2.Func(5, 5)
                        from op3 in operators
                        let v3 = (op3.Name == "/" && v2 == 0) ? null : (int?)op3.Func(v1, v2)
                        where v3 == i
                        select "(5" + op1.Name + "5)" + op2.Name + "(5"
                             + op3.Name + "5)"
                      ).FirstOrDefault()
              };

foreach (var opt in options)
        {
            Console.WriteLine(opt.i + ": " + opt.op);
        }

修改
关于let v3 = (op3.Name == "/" && v2 == 0) ? null : (int?)op3.Func(v1, v2)的几句话:这是一种非常有效的方法,可以避免除以0(这可能会发生,因为你可以除以(5-5))。

我很确定你可以用更好的方式过滤它,但是我把它留给enphasize这个问题可以发生。

答案 3 :(得分:1)

假设您不想使用LINQ,这是一种实现方法。这说它是非常不优化的,我建议使用更短的LINQ实现。 (见:Marc Gravell's post。)

using System;
using System.Collections.Generic;

namespace MathIterator
{
  class Program
  {
    static readonly int[] _inputs = new int[] { 5, 5, 5, 5 };
    static readonly char[] _operations = new char[] { '+', '-', '*', '/' };
    static Dictionary<int, List<string>> _calculations = new Dictionary<int, List<string>>();

    static void Main(string[] args)
    {
      StartPermutation();
      PrintResults();
    }

    static void StartPermutation()
    {
      if (_inputs.Length > 0)
        Permute(1 /*index*/, _inputs[0], _inputs[0].ToString());    
    }

    static void Permute(int index, int result, string computation)
    {
      if (index == _inputs.Length)
      {
        if (!_calculations.ContainsKey(result))
        {
          _calculations[result] = new List<string>();
        }

        _calculations[result].Add(computation);
      }
      else
      {
        foreach (char operation in _operations)
        {
          string nextComputation = String.Format("({0} {1} {2})",computation, operation, _inputs[index]);
          int nextResult = result;

          switch (operation)
          {
            case '+':
              nextResult += _inputs[index];
              break;
            case '-':
              nextResult -= _inputs[index];
              break;
            case '*':
              nextResult *= _inputs[index];
              break;
            case '/':
              nextResult /= _inputs[index];
              break;
          }

          Permute(
            index + 1,
            nextResult,
            nextComputation);
        }
      }
    }

    static void PrintResults()
    {
      for (int i = 1; i <= 10; ++i)
      {
        if (_calculations.ContainsKey(i))
        {
          Console.WriteLine("Found {0} entries for key {1}", _calculations[i].Count, i);

          foreach (string calculation in _calculations[i])
          {
            Console.WriteLine(i + " = " + calculation);
          }
        }
        else
        {
          Console.WriteLine("No entry for key: " + i);
        }
      }
    }
  }
}

这是另一种实现。这个遵循优先顺序。同样,我不建议像这样解决它。甚至更多 - 所以现在给予广泛的破解(以区别于减号),但它似乎确实有效。

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace MathIterator
{
  class Program
  {
    static readonly int[] _inputs = new[] { 5, 5, 5, 5 };
    //HUGE hack, the '–' is a wide dash NOT a hyphen.
    static readonly char[][] _operationLevels = new[] { new[] { '*', '/' }, new[] { '+', '–' } };
    static List<string> _calculations = new List<string>();
    static Dictionary<int, List<string>> _results = new Dictionary<int, List<string>>();

    static void Main(string[] args)
    {
      StartPermutation();
      StartEvaluateCalculations();
      PrintResults();
    }

    static void StartPermutation()
    {
      if (_inputs.Length > 0)
        Permute(1 /*index*/, _inputs[0].ToString());    
    }

    static void Permute(int index, string computation)
    {
      if (index == _inputs.Length)
      {
        _calculations.Add(computation);
      }
      else
      {
        foreach (char[] operationLevel in _operationLevels)
        {
          foreach (char operation in operationLevel)
          {
            string nextComputation = String.Format("{0} {1} {2}", computation, operation, _inputs[index]);
            Permute(
              index + 1,
              nextComputation);
          }
        }
      }
    }

    static void StartEvaluateCalculations()
    {
      foreach (string calculation in _calculations)
      {
        int? result = EvaluateCalculation(calculation);

        if (result != null)
        {
          int intResult = (int) result;

          if (!_results.ContainsKey(intResult))
          {
            _results[intResult] = new List<string>();
          }

          _results[intResult].Add(calculation);            
        }
      }
    }

    static int? EvaluateCalculation(string calculation)
    {
      foreach (char[] operationLevel in _operationLevels)
      {
        string[] results = calculation.Split(operationLevel, 2);

        if (results.Length == 2)
        {
          int hitIndex = results[0].Length;

          Regex firstDigit = new Regex(@"^ -?\d+");
          Regex lastDigit = new Regex(@"-?\d+ $");

          string firstMatch = lastDigit.Match(results[0]).Value;
          int arg1 = int.Parse(firstMatch);

          string lastMatch = firstDigit.Match(results[1]).Value; 
          int arg2 = int.Parse(lastMatch);

          int result = 0;

          switch (calculation[hitIndex])
          {
            case '+':
              result = arg1 + arg2;
              break;
            //HUGE hack, the '–' is a wide dash NOT a hyphen.
            case '–':
              result = arg1 - arg2;
              break;
            case '*':
              result = arg1 * arg2;
              break;
            case '/':
              if ((arg2 != 0) && ((arg1 % arg2) == 0))
              {
                result = arg1 / arg2;
                break;
              }
              else
              {
                return null;
              }
          }

          string prePiece = calculation.Remove(hitIndex - 1 - arg1.ToString().Length);
          string postPiece = calculation.Substring(hitIndex + 1 + lastMatch.ToLower().Length);

          string nextCalculation = prePiece + result + postPiece;
          return EvaluateCalculation(nextCalculation);
        }
      }

      return int.Parse(calculation);
    }

    static void PrintResults()
    {
      for (int i = 1; i <= 10; ++i)
      {
        if (_results.ContainsKey(i))
        {
          Console.WriteLine("Found {0} entries for key {1}", _results[i].Count, i);

          foreach (string calculation in _results[i])
          {
            Console.WriteLine(i + " = " + calculation);
          }
        }
        else
        {
          Console.WriteLine("No entry for key: " + i);
        }
      }
    }
  }
}

答案 4 :(得分:1)

这是一个完全基于LINQ(方法语法)和后期评估的解决方案,它可以处理所有排列(不仅仅是从左到右):

static void Main()
{
    var solution = PermuteLength(4)
        .Where(p => Decimal.Floor(p.Value) == p.Value)
        .Where(p => p.Value <= 10 && p.Value >= 0)
        .OrderBy(p => p.Value);

    foreach (var p in solution)
    {
        Console.WriteLine(p.Formula + " = " + p.Value);
    }
}

public static Operator[] Operators = new[]
    {
        new Operator {Format = "({0} + {1})", Function = (x, y) => x + y},
        new Operator {Format = "({0} - {1})", Function = (x, y) => x - y},
        new Operator {Format = "({1} - {0})", Function = (x, y) => y - x},
        new Operator {Format = "({0} * {1})", Function = (x, y) => x * y},
        new Operator {Format = "({0} / {1})", Function = (x, y) => y == 0 ? 0 : x / y},
        new Operator {Format = "({1} / {0})", Function = (x, y) => x == 0 ? 0 : y / x},
    };

public static IEnumerable<Permutation> BasePermutation = new[] { new Permutation {Formula = "5", Value = 5m} };

private static IEnumerable<Permutation> PermuteLength(int length)
{
    if (length <= 1)
        return BasePermutation;

    var result = Enumerable.Empty<Permutation>();

    for (int i = 1; i <= length / 2; i++)
        result = result.Concat(Permute(PermuteLength(i), PermuteLength(length - i)));

    return result;
}

private static IEnumerable<Permutation> Permute(IEnumerable<Permutation> left, IEnumerable<Permutation> right)
{
    IEnumerable<IEnumerable<IEnumerable<Permutation>>> product = left.Select(l => right.Select(r => ApplyOperators(l, r)));

    var aggregate =
        product.Aggregate(Enumerable.Empty<IEnumerable<Permutation>>(), (result, item) => result.Concat(item)).
            Aggregate(Enumerable.Empty<Permutation>(), (result, item) => result.Concat(item));

    return aggregate;
}

private static IEnumerable<Permutation> ApplyOperators(Permutation left, Permutation right)
{
    return Operators.Select(o => new Permutation
    {
        Formula = string.Format(o.Format, left.Formula, right.Formula),
        Value = o.Function(left.Value, right.Value)
    });
}

public struct Permutation
{
    public string Formula;
    public decimal Value;
}

public struct Operator
{
    public string Format;
    public Func<decimal, decimal, decimal> Function;
}

已知问题: 有些解决方案是重复的 不能很好地处理除零,所以一些错误的答案(我假设任何除以零= 0)

编辑: 结果的一部分:

((5/5)/(5/5))= 1

((5/5)+(5/5))= 2

((5 +(5 + 5))/ 5)= 3

(5 - ((5 + 5)/ 5))= 3

<(>((5 * 5) - 5)/ 5)= 4

(5 +(5 *(5 - 5)))= 5

(5 - (5 *(5 - 5)))= 5

(5 +((5-5)/ 5))= 5

(5 - ((5 - 5)/ 5))= 5