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

我目前正在build立一个半复杂的计算器,这个计算器基本上是从我提供的Excel电子表格转换而来的。

我已经掌握了大部分内容,但Excel电子表格中有一部分是在6行和7列之间进行多次计算的,但问题在于,计算并没有按照特定的顺序发生。

因此,例如,使用(Row2[Column4] * Row2[Column5])计算(Row4[Column2] / Row5[Column1])使用(Row4[Column2] / Row5[Column1])计算Row1[Column4]等等。 。

我曾经想过使用二维数组,但是恐怕这些数值会按照特定的顺序计算,因此当它们到达时没有任何价值。 据我所知, Row1将首先计算,然后Row2Row3

所以,没有为我的Excel电子表格中的每个单元格创build一个variables(并相应地sorting),有没有一种方法可以使用C#来计算?

我真的很感激任何帮助,build议,指针,无论你认为可能 – 我很乐意听到它!

编辑实现由@dtb提供的Lazy类后,我有以下代码。 这是我提供的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.

谷歌search错误已经返回了一堆垃圾searchtypes的网站。

马尔科

看看懒惰评估

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

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

输出:

行= 0列= 0值= 284
行= 0列= 1值= 42
行= 1列= 0值= 100
行= 1列= 1值= 142

LINQ-to-Lazy变得更可读:

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

自定义replace.NET 4.0的Lazy <T>类 :

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

马可,我认为最好的方法是让你绘制出这些细胞之间的关系。 如果这个问题是关于Excel的顺序,那么我可以把你指向这里: http : //msdn.microsoft.com/en-us/library/bb687891.aspx

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

计划A

你可以很容易地编写你自己的Lazy<T>版本(这是未经testing的代码):

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

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

B计划

解决您的问题的另一种方法是将您的单元格按增加的依赖性顺序排列(如果A包含直接或间接使用B的公式,则单元格A依赖于单元格B),然后按照该顺序对其进行评估。

警告

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

希望这可以帮助。