1

私は現在、提供されたExcelスプレッドシートからの変換である半複雑な計算機を構築しています。

私はそのほとんどを釘付けにしましたが、Excelスプレッドシートには、6行7列の間で複数の計算が行われる部分がありますが、問題は、計算が特定の順序でまったく行われないことです。

したがって、たとえば、Row0[Column1]を使用して計算され、を使用(Row2[Column4] * Row2[Column5])Row1[Column4]て計算され(Row4[Column2] / Row5[Column1])ます。

2D配列を使用することを考えましたが、値が特定の順序で計算されるため、値に達したときに値がないのではないかと心配しています。私の知る限り、Row1が最初に計算され、次にRow2Row3などが計算されます。

したがって、Excelスプレッドシートの各セルに変数を作成せずに(そして適切に順序付けせずに)、C#を使用してこれを計算する方法はありますか?

私はあなたが可能であると思うものは何でも、どんな助け、アドバイス、ポインタ、本当に感謝します-私はそれを聞きたいです!

編集@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.

エラーをグーグルで検索すると、スパム検索タイプのWebサイトが多数返されます。

マルコ

4

3 に答える 3

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

テーブルセルの内容が任意の順序でどのように定義されているかに注意してください。セル間に循環依存関係がない限り、順序自体を把握します。

出力:

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

.NET4.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;
        }
    }
}
于 2010-09-14T21:16:40.483 に答える
0

マルコ、私はあなたがこれらの細胞間の関係を計画するのが最善の方法だと思います。この質問がExcelが実行する順序に関するものである場合は、ここを参照できます:http: //msdn.microsoft.com/en-us/library/bb687891.aspx

于 2010-09-14T21:21:58.823 に答える
0

上に示した怠惰な解決策は最もエレガントですが、以下に1つの注意点があります。

プラン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;
  }
}

もちろん、オーバーロードされた算術演算子も定義する必要があります。

次のプラン

問題に取り組む別の方法は、セルを依存関係の昇順で並べ替え(Aに直接または間接的にBを使用する数式が含まれている場合、セルAはセルBに依存します)、その順序で評価することです。

警告

依存関係にサイクルが含まれている場合は、固定小数点まで評価する必要があるため、これらのアプローチのいずれも機能することが保証されていません。その場合、おそらくプランBのようなものが必要ですが、最初に依存関係グラフを強力に接続されたコンポーネントに分割します(このサイトのSCCには良い答えがあります)。

お役に立てれば。

于 2010-09-14T22:58:25.920 に答える