创建“随着时间的推移”算法

时间:2010-07-19 17:19:09

标签: c# .net algorithm design-patterns

我所拥有的是一个LineItem对象和一个名为LineItems的集合,它包含LineItem对象。我的LineItem对象有一个名为ItemDate(DateTime数据类型)的属性和另一个名为ItemAmount(十进制数据类型)的属性,另一个属性叫做ItemCategory(整数数据类型)。

我要做的是在我的集合对象中编写一个函数,该函数将返回该类别中具有最高总和(ItemAmount)的整数类别。例如,如果我有这个:

对象1:

ItemAmount = 50.00

ItemCategory = 1

对象2:

ItemAmount = 25

ItemCategory = 1

对象3:

ItemAmount = 535.00

ItemCategory = 2

好的,在这个例子中,函数应返回2,因为ItemCategory 2的ItemAmount(535)大于ItemCategory 1(50 + 25 = 75)。

我知道怎么做。更难的是我需要它能够随着时间的推移这样做,这意味着,如果金额很大,如535,但是其他一些对象的金额较小,但是它们中有更多的更接近日期,那么它需要在技术上比其他数量“更大”。这几乎就像需要考虑频率的金额一样。每天发生10美元的金额需要比每年发生的500美元“更大”,即使每天500美元大于10美元。这几乎就像我需要通过一年的放大镜来查看一个月的数据。

我希望这个问题有道理。

2 个答案:

答案 0 :(得分:1)

试试这个:

class ListItem
{
    internal DateTime When;
    internal decimal Amount;
    internal int Category;
}

class ListItems
{
    internal List<ListItem> _items = new List<ListItem>();
    internal int GetCategory(DateTime from, DateTime to)
    {
        Dictionary<int, decimal> totals = _items
            .Where(y => y.When >= from && y.When < to)
            .GroupBy(x => x.Category)
            .ToDictionary(
                category => category.Key,
                category => category.Sum(item => item.Amount)
            );
        return totals.Keys
            .Where(category => totals[category] == totals.Values.Max())
            .First();
    }
}

Linq有点满口,但如果我正确理解了这个问题,我认为它会起作用。

答案 1 :(得分:1)

听起来你可能想要一个旅行窗口总和:选择一个时间段(比方说30天),并跟踪该窗口中的项目总数。

如果您只想要一个实例(例如,现在结束30天),当然您需要做的就是在窗口中总结这些项目。但是,如果您想绘制图形,最有效的方法是对项目进行排序,并执行运行累积;添加进入窗口的项目,并减去留下的项目。

要实现移动窗口,可以将两个迭代器用于排序列表(以下是伪代码,而不是C#):

// initialize
acc= 0.0
for(startP= SortedItems.begin; !startP.last; startP.next) {
  if(startP.item.time > graphstart - timewindow) { break }
}
for(endP= startP; !endP.last; endP.next) {
  acc += endP.item.value
  if(endP.item.time > graphstart) { break }
}

// main loop
for(; !endP.last; endP.next) { // advance time window to next item
  endItem= endP.item
  endTime= endItem.time
  for(; !startP.last; startP.next) { // subtract items leaving time window
    startItem= startP.item
    startTime= startItem.time
    if(startTime > endTime - timewindow) { break }
    acc -= startItem.value
    output(startTime + timewindow, acc)  // register graph values coming down
  }
  acc += endItem.value
  output(endTime, acc)  // register graph value going up
}