当时间可变时,数据聚合随着时间的推移而变化

时间:2012-09-13 08:35:43

标签: c# aggregation modulo

我正在开发一个应用程序,用于计算在指定时间段(期限)内在产品中获得的共享。

在执行计算后,我有必要根据预定义的审核期将数据汇总到组中(例如,如果获得100%产品所有权所需的时间是25年,那么审核期间价值是5年,我将有5套协议的数据汇总。

我通过循环计算结果集来执行聚合:

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

这在大多数情况下都能正常工作。 但是我确实有很多场景,产品在学期结束前达到100%的所有权。

我需要做的是汇总基于ReviewPeriod变量执行的计算,但如果计算中的最终值不等于审核周期,则根据剩余的项目数汇总项目

例如,给定22年的期限,数据将根据Review Period变量进行汇总,但如果有余数,则应根据余数的值汇总余数。

工作示例

0 - 5年级= 5次聚合

第6 - 10年= 5次聚合

11 - 15年级= 5次聚合

16 - 20年= 5次聚合

21 - 22年= 2次聚合

如我所述,任何人都可以帮助我使用逻辑来聚合数据。

6 个答案:

答案 0 :(得分: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();
            }
        }
    }
}

答案 1 :(得分:1)

我认为我的建议不值得300rep赏金,要么我误解了你的问题,要么你已经超过了赏金..

计算最终聚合的现有代码是否运行良好?如果是这样,那么确定范围你可以使用modulo(%)和简单的数学:

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%所有权的情况”。 - 这表明你宁愿在计算中出错,而不是在循环中出错。如果错误在循环或年边界检测中,则可能几乎所有都将关闭。如果没有更多的计算代码被揭示,很难说。

答案 2 :(得分: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.
}

答案 3 :(得分: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);
            }
        }

答案 4 :(得分: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)
{
    //...
}

答案 5 :(得分: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