2

私は、指定された期間(期間)に製品で取得された共有を計算するアプリケーションを開発中です。

計算が実行された後、事前定義されたレビュー期間に基づいてデータをグループに集約する必要があります(たとえば、製品の100%の所有権を取得するために必要な時間が25年で、レビュー期間の値が5の場合)何年もの間、私は合意のために5セットのデータ集約を持っているでしょう)。

計算結果セットをループして示すように、集計を実行します。

if (Year% ReviewPeriod == 0)
            {
                // Perform Aggregations
            }

これはほとんどのシナリオで正常に機能します。ただし、期間が終了する前に製品の所有権が100%に達するシナリオはいくつかあります。

ReviewPeriod変数に基づいて実行された計算を集計する必要がありますが、計算の最終的な値の数がレビュー期間と等しくない場合は、残りのアイテムの数に基づいてアイテムを集計します。

たとえば、22年の期間が与えられた場合、データはレビュー期間変数に基づいて集計されますが、余りがある場合は、余りの値に基づいて余りを集計する必要があります。

実施例

0年目-5=5つの集計

6年目-10=5つの集合体

11年目-15=5つの集合体

16〜20年=5つの集計

21〜22年=2つの集計

私が説明したように、誰かがデータを集約するロジックを手伝ってくれませんか。

4

6 に答える 6

1

このデータがメモリ内にあると仮定すると(特に指定していないため)、LinqのGroupBy関数を使用できます。

struct YearValue 
{
    public int Year, Value; 
}

static void Main()
{
    // Create some data, hopefully representative of what you are dealing with...
    Random r = new Random();
    YearValue[] dataValues = new YearValue[22];
    for (int i = 0; i < dataValues.Length; i++)
        dataValues[i] = new YearValue {Year = i, Value = r.Next(200)};

    // Average of values across 'ReviewPeriod' of five:
    foreach (var item in dataValues.AsEnumerable().GroupBy(i => i.Year / 5))
    {
        YearValue[] items = item.ToArray();
        Console.WriteLine("Group {0} had {1} item(s) averaging {2}",
                          item.Key,
                          items.Length,
                          items.Average(i => i.Value)
            );
    }
}

次に、このプログラムは次のテキストを出力します。

Group 0 had 5 item(s) averaging 143.6
Group 1 had 5 item(s) averaging 120.4
Group 2 had 5 item(s) averaging 83
Group 3 had 5 item(s) averaging 145.2
Group 4 had 2 item(s) averaging 98.5
于 2012-09-19T00:56:47.283 に答える
1

あなたは次のようなことを考えますか

private int reviewPeriod = 5;

public void Aggregate(int term)
{
    Enumerable.Range(0, term)
        .ToList()
        .Foreach(this.AggregateYear);
}

this.AggregateYearが次のように定義されている場合

public void AggregateYear(int year)
{
    var currentRemainder = year % this.reviewPeriod;
    var aggregatePeriod = (currentRemainder == 0)
        ? this.reviewPeriod
        : currentRemainder;
    this.PerformAggregation(aggregatePeriod);
}

そしてthis.PerformAggregation次のように定義されます

private void PerformAggregation(int aggregatePeriod)
{
    //...
}
于 2012-09-18T13:00:56.433 に答える
1

おそらく最も簡単な方法は次のようになります。

for ( int year = 0; year <= max_year; year++ ) {
    if ( year % reviewPeriod == 0 ) {
        // start a new aggregation
    }
    // add year to current aggregation
}

集計のリストを保持し、各期間の開始時に新しい集計を追加できます。

これは、年をリストにグループ化するだけの実用的な例です。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Aggregations
{
    class Program
    {
        static void Main(string[] args)
        {
            int maxYear = 22;
            int period = 5;
            int year = 1985;

            List<List<int>> aggregations = new List<List<int>>();
            int i = -1;
            for (int y = 0; y <= maxYear; y++)
            {
                if (y % period == 0)
                {
                    aggregations.Add(new List<int>());
                    i++;
                }
                aggregations.ElementAt(i).Add(year);
                year++;
            }
            foreach ( List<int> l in aggregations )
            {
                foreach (int yy in l)
                {
                    Console.Write(yy + " ");
                }
                Console.WriteLine();
            }
        }
    }
}
于 2012-09-18T12:36:12.477 に答える
1

私の提案は300repの報奨金の価値がないと思います。私があなたの問題を誤解したか、あなたが報奨金を超過しました。

最終的な集計を計算する既存のコードはうまく機能しますか?その場合、範囲を決定するには、モジュロ(%)と簡単な計算を使用します。

int minYear = ...the first year // inclusive, i.e. 1970
int maxYear = ...the last year // inclusive, i.e. 2012

int span = maxYear - minYear + 1; // 1970..2012->43, 2001..2006->6

int fullFives = span / 5; // 1970..2012->8, 2001..2006->1
int remainder = span % 5; // 2001..2006->3, 2001..2006->1

for(int i=0; i<fullFives; ++i)
{
    int yearFrom = minYear + 5*i
    int yearTo = minYear + 5*(i+1) - 1

    // 1970..2012 -> 1970-1974, 1975-1979,1980-1984,1985-1989,1990-1994,1995-1999,2000-2004,2005-2009
    // 2001..2006 -> 2001-2005

    aggregate(yearFrom, yearTo);
}

if(remainder > 0)
{
    int yearFrom = minYear + 5*fullFives
    int yearTo = minYear + maxYear

    // 1970..2012 -> 2010-2012
    // 2001..2006 -> 2006-2006

    aggregate(yearFrom, yearTo);
}

これは「薄気味悪い」と書かれていますが、私はそれをチェック/コンパイルしていません-それは単にアイデアをスケッチするためのものです。

注:すべてが機能するとおっしゃっていますが、「期間が終了する前に製品が100%の所有権に達するシナリオがいくつかあります」。-これは、ループではなく、計算にエラーがあることを示しています。エラーがループまたは年の境界の検出にあった場合、おそらくほとんどすべてがオフになります。より多くの計算コードが明らかにされなければ、言うのは難しいです。

于 2012-09-18T12:39:28.620 に答える
1

続行するのに十分なコードを実際に提供していません。うまくいけば、これを使用できるはずですが、ループは現在設定されています。mod値をループの外側に「リーク」します。ループが終了したら、最終的なmod値をチェックして、残っている集計の数を確認できます。

int modValue = 0;
for //foreach/while/... - your loop here
{
    ...
    modValue = Year % ReviewPeriod;
    if (modValue == 0)
    {
        // Perform Aggregations
    }  
    ...
} // end of your loop

if (modValue != 0)
{
    // Perform final aggregation. There are modValue items to aggregate.
}
于 2012-09-18T12:40:51.990 に答える
1

コードサンプルは、毎年ではなく、0、5、10年などに起動します。

そのコードが起動するときに集計するのに年数が必要であり、製品が早期に100%の所有権に達したときに期間を事前に設定できる場合は、これでうまくいくと思います。

        int term = 22;
        int reviewperiod = 5;

        for (int year = 0; year < term; year++)
        {
            if (year % reviewperiod == 0)
            {
                var endyear = Math.Min(year + reviewperiod, term);
                Console.WriteLine("Aggregate years {0} to {1}, {2} Aggregations ", year, endyear, endyear - year);
            }
        }
于 2012-09-18T12:45:14.527 に答える