代码之家  ›  专栏  ›  技术社区  ›  Marko

计算C#(从Excel转换公式)中的值数组

  •  1
  • Marko  · 技术社区  · 14 年前

    我目前正在建立一个半复杂的计算器,这基本上是一个Excel电子表格,我已经提供了转换。

    我已经搞定了大部分内容,但Excel电子表格中有一部分在6行到7列之间进行了多次计算,但问题是这些计算并没有按特定的顺序进行。

    比如说, Row0[Column1] 使用以下公式计算 (Row2[Column4] * Row2[Column5]) Row1[Column4] 使用以下公式计算 (Row4[Column2] / Row5[Column1]) 以此类推。。你明白了。

    第1行 第2行 第3行 等等。

    在实现了 ,我有以下代码。这是Excel电子表格的直接副本,包括指针和计算。

    var sr = new Lazy<decimal>[6, 6];
    sr[0, 0] = new Lazy<decimal>(() => sr[1, 0].Value - eNumber);
    sr[0, 3] = new Lazy<decimal>(() => sr[0, 4].Value - sr[1, 0].Value - sr[1, 4].Value);
    sr[0, 4] = new Lazy<decimal>(() => sr[0, 0].Value * edD);
    sr[0, 5] = new Lazy<decimal>(() => sr[0, 0].Value);
    
    sr[1, 0] = new Lazy<decimal>(() => sr[1, 5].Value);
    sr[1, 4] = new Lazy<decimal>(() => sr[1, 0].Value * edD);
    sr[1, 5] = new Lazy<decimal>(() => sr[2, 0].Value + sr[2, 5].Value);
    
    sr[2, 0] = new Lazy<decimal>(() => eNumber * rRate);
    sr[2, 4] = new Lazy<decimal>(() => sr[2, 0].Value * hdD);
    sr[2, 5] = new Lazy<decimal>(() => sr[1, 5].Value);
    
    sr[3, 1] = new Lazy<decimal>(() => sr[2, 5].Value);
    
    sr[4, 2] = new Lazy<decimal>(() => eNumber * (ePc / 100) + sr[2, 0].Value * (hlPc / 100) - sr[3, 1].Value);
    
    sr[5, 0] = new Lazy<decimal>(() => (sr[0, 0].Value + sr[1, 0].Value + sr[2, 0].Value) / ePerR);
    sr[5, 2] = new Lazy<decimal>(() => sr[5, 0].Value / rLifecycle);
    sr[5, 4] = new Lazy<decimal>(() => sr[5, 2].Value);
    sr[5, 5] = new Lazy<decimal>(() => sr[5, 0].Value + sr[5, 2].Value - sr[5, 4].Value);
    

    但是我得到以下错误
    ValueFactory attempted to access the Value property of this instance.

    谷歌搜索这个错误已经返回了一堆垃圾搜索类型的网站。

    马尔科

    3 回复  |  直到 13 年前
        1
  •  6
  •   dtb    14 年前

    看一看 :

    var table = new Lazy<int>[2, 2];
    
    table[0, 0] = new Lazy<int>(() => table[1, 1].Value * 2);
    table[0, 1] = new Lazy<int>(() => 42);
    table[1, 0] = new Lazy<int>(() => 100);
    table[1, 1] = new Lazy<int>(() => table[0, 1].Value + table[1, 0].Value);
    
    for (int i = 0; i < 2; i++)
    for (int j = 0; j < 2; j++)
    {
        Console.WriteLine("Row = {0}  Column = {1}  Value = {2}",
                                 i,            j,           table[i, j].Value);
    }
    

    请注意表单元格的内容是如何按任意顺序定义的。只要单元格之间没有循环依赖关系,它就可以自己计算顺序。

    输出:

    Row = 0  Column = 0  Value = 284
    Row = 0  Column = 1  Value = 42
    Row = 1  Column = 0  Value = 100
    Row = 1  Column = 1  Value = 142
    

    它变得更容易阅读 :

    var table = new Lazy<int>[2, 2];
    
    table[0, 0] = from t in table.AsLazy()
                  from x in t[1, 1]
                  select 2 * x;
    table[0, 1] = 42.AsLazy();
    table[1, 0] = 100.AsLazy();
    table[1, 1] = from t in table.AsLazy()
                  from a in t[0, 1]
                  from b in t[1, 0]
                  select a + b;
    

    使用

    static class LazyExtensions
    {
        public static Lazy<TResult> SelectMany<TSource, TCollection, TResult>(this Lazy<TSource> source, Func<TSource, Lazy<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector)
        {
            return new Lazy<TResult>(() => resultSelector(source.Value, collectionSelector(source.Value).Value));
        }
    
        public static Lazy<TSource> AsLazy<TSource>(this TSource value)
        {
            return new Lazy<TSource>(() => value);
        }
    }
    

    Lazy<T> Class :

    sealed class MyLazy<T>
    {
        private readonly Func<T> valueFactory;
        private T value;
        private bool valueCreated;
    
        public MyLazy(Func<T> valueFactory)
        {
            if (valueFactory == null)
            {
                throw new ArgumentNullException("valueFactory");
            }
            this.valueFactory = valueFactory;
        }
    
        public bool IsValueCreated
        {
            get { return this.valueCreated; }
        }
    
        public T Value
        {
            get
            {
                if (!this.valueCreated)
                {
                    this.value = this.valueFactory();
                    this.valueCreated = true;
                }
                return this.value;
            }
        }
    }
    
        2
  •  0
  •   mkoistinen    14 年前

    马尔科,我认为最好的办法是你找出这些细胞之间的关系。如果这个问题是关于Excel的操作顺序,我可以在这里指出: http://msdn.microsoft.com/en-us/library/bb687891.aspx

        3
  •  0
  •   Rafe    14 年前

    上面显示的懒惰解决方案是最优雅的,我将在下面提到一个警告。

    您可以编写自己版本的 Lazy<T> 非常容易(这是未经测试的代码):

    class Lazy<T> {
      private bool IsEvaluated;
      private T Value;
      private Func<T> Suspension;
      public Lazy<T>(Func<T> susp) { Suspension = susp; }
      public static implicit operator T(Lazy<T> thunk) {
        if (thunk.IsEvaluated) {
          return thunk.Value;
        }
        thunk.Value = thunk.Suspension();
        thunk.IsEvaluated = true;
        return thunk.Value;
      }
    }
    

    当然,还需要定义重载算术运算符。

    解决问题的另一种方法是将单元格排序为递增的依赖顺序(如果A包含直接或间接使用B的公式,则单元格A依赖于单元格B),并按该顺序计算它们。

    如果您的依赖项包含一个循环,那么这两种方法都不能保证工作,因为您将需要计算到一个固定点。在这种情况下,您可能需要类似计划B的内容,但首先要将依赖关系图分解为强连接的组件(在这个站点的SCC上有一个很好的答案)。