1

我目前正在構建一個半複雜的計算器,它基本上是從我提供的Excel電子表格轉換而來的。在C#中計算值的數組(從Excel轉換公式)

我已經掌握了大部分內容,但Excel電子表格中有一部分在6行和7列之間進行多次計算,但問題在於計算的發生並不是特定的順序。

因此,例如,Row0[Column1]使用(Row2[Column4] * Row2[Column5])Row1[Column4]使用(Row4[Column2]/Row5[Column1])等計算計算..你的想法。

我想過使用二維數組,但恐怕值會按特定順序計算,因此在到達時沒有值。據我所知,ROW1將首先計算,然後行2ROW3

因此,沒有在我的Excel電子表格中每個單元創建一個變量(並適當地訂購吧) ,有沒有一種方法可以使用C#來計算?

我真的很感激任何幫助,建議,指針,無論你認爲可能 - 我很樂意聽到它!

編輯落實@dtb提供的懶惰下課後,我有下面的代碼。這是我提供的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.

谷歌搜索錯誤返回一堆垃圾搜索型網站。

馬爾科

+0

它是什麼樣的錯誤?編譯器錯誤或異常?你有沒有增強懶惰類來做循環依賴檢測?因爲你的定義中有一個:sr [1,5]用sr [2,5]定義,反之亦然。 – dtb 2010-09-15 00:28:07

+0

嗨@dtb - 項目編譯,但我得到一個例外。我暫時使用了.NET 4(直到我在原始類中使用它)。順便說一句,我不確定如何擴展循環依賴的類,這(有點)超出了我的知識範圍。 – Marko 2010-09-15 00:32:52

+0

然後你剛剛遇到.NET 4.0 Lazy類的循環依賴檢測。你可以通過在調用valueFactory之前將valueCreated設置爲1 *,在2之後通過設置valueCreated來實現它,並且在調用Value並且valueCreated爲1時拋出異常...仔細檢查Excel表單中是否真的存在循環定義。如果有,使用Excel公式發佈一個新問題,並詢問如何計算C#中的修復點。但是我懷疑你的代碼中存在拼寫錯誤。 – dtb 2010-09-15 00:45:07

回答

6

看一看延遲計算

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 

變得稍微更易讀與LINQ到懶惰

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

.NET 4的自定義替換。0的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; 
     } 
    } 
} 
+0

是懶惰的自定義類嗎?我使用的是WPF(.NET 3.5),而懶惰不存在。 – Marko 2010-09-14 21:45:03

+0

[Lazy ](http://msdn.microsoft.com/en-us/library/dd642331.aspx)是.NET Framework 4.0中的新增功能。如果你堅持使用3.5,你應該能夠很容易地構建一個自定義替換。 – dtb 2010-09-14 21:49:37

+0

是的,我在這個問題上遇到了3.5(我正在嘗試使用你提供的自定義方法) – Marko 2010-09-14 21:56:43

0

上面顯示的懶惰解決方案是最優雅的,有一個警告,我會在下面提到。

A計劃

你可以編寫你自己的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; 
    } 
} 

當然,你需要定義重載算術運算符如好。

計劃B

解決的問題的另一種方法是將細胞分類到增加依賴順序(其中小區A依賴於小區B,如果A包含使用乙式,直接或間接地),並評價他們按照這個順序。

買者

如果你的依賴包含一個週期,然後,這些方法都不是保證工作,因爲你將需要評估,以一個固定的點。在這種情況下,您可能需要類似於計劃B的內容,但首先將您的依賴關係圖分解爲強連接的組件(本網站上的SCC有一個很好的答案)。

希望這會有所幫助。