2

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

计算完成后,我有必要根据预定义的审查期将数据汇总到组中(例如,如果获得产品 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 个聚合

正如我所描述的那样,任何人都可以帮助我汇总数据的逻辑。

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

我认为我的建议不值得 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 回答
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

你有没有想过像

private int reviewPeriod = 5;

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

whenthis.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 回答