2008-10-17 49 views
2

编辑:我错过了关键的一点:.NET 2.0通过列表进行遍历和动态创建汇总行

考虑在那里我有未排序的项目列表的情况下,对一类简单起见像这样:

class TestClass 
{ 
    DateTime SomeTime; 
    decimal SomePrice; 

    // constructor 
} 

我需要创建一个报告状输出,其中总价格为每一天累积。每个项目应该有一行,由相应的摘要行组成。

参与我们的测试数据:

List<TestClass> testList = new List<TestClass> { 
new TestClass(new DateTime(2008,01,01), 12), 
new TestClass(new DateTime(2007,01,01), 20), 
new TestClass(new DateTime(2008,01,01), 18) 
}; 

所需的输出会是这样的:

2007-01-01: 
20 
Total: 20 

2008-01-01: 
12 
18 
Total: 30 

什么是接近这样的情况下最好的方法是什么?在这种列表的情况下,我将实现TestClass的IComparable接口,以便列表可以排序。

要创建报告本身,这样的事情也可以使用(假设我们有像积累的价格,跟踪当前日期等任务的方法):

for (int i=0;i<testList.Count;i++) 
{ 
    if (IsNewDate(testList[i])) 
    { 
     CreateSummaryLine(); 
     ResetValuesForNewDate(); 
    } 

    AddValues(testList[i]); 
} 

// a final summary line is needed to include the data for the last couple of items. 
CreateSummaryLine(); 

这工作好了,但就第二个“CreateSummaryLines”而言,我有一种奇怪的感觉。

你在哪些方面处理这种情况(特别是考虑到事实,我们需要使用项目清单<>而不是预先分类的词典或类似的东西)?

回答

2

由于您在C#3.0中使用.NET 2.0,因此您可以使用LINQBridge来启用此功能。

LINQ;如:

 var groups = from row in testList 
        group row by row.SomeTime; 
     foreach (var group in groups.OrderBy(group => group.Key)) 
     { 
      Console.WriteLine(group.Key); 
      foreach(var item in group.OrderBy(item => item.SomePrice)) 
      { 
       Console.WriteLine(item.SomePrice); 
      } 
      Console.WriteLine("Total" + group.Sum(x=>x.SomePrice)); 
     } 
+0

错过了重要的信息 – Grimtron 2008-10-17 12:51:02

2

关键问题:您是否使用.NET 3.5,从而允许使用LINQ?如果是这样,您可以按照SomeTime.Date进行分组,然后分别处理每个日期。

如果你有大量的数据,你会发现我的Push LINQ项目有用的 - 但除此之外,直LINQ到对象是你最好的选择。

+0

错过了重要的信息:.NET 2.0要使用的。 .NET 2.0的使用:因为你似乎可以用C#3.0 – Grimtron 2008-10-17 12:50:10

+0

然后使用LINQBridge。 – 2008-10-17 12:50:46

1

您使用的是什么版本的C#/ .NET?如果你是最新的,看看LINQ。这允许分组数据。在你的情况,你按日期能集团:

var days = from test in testList group test by test.SomeTime; 
foreach (var day in days) { 
    var sum = day.Sum(x => x.SomePrice); 
    Report(day, sum); 
} 

这种方式,你可以为每个day报告值的列表,用钱的那一天总和一起。

0

所需输出感觉就像你想表示你的汇总数据的数据结构。您想将日期与TestClass对象列表配对,然后获得这些对象的集合。你可以使用一个HashSet或一个字典作为集合。

对于总结,对数据结构能为你实现的ToString。

3

好了,如果你不能使用LINQ:

(我使用VAR,以节省空间,但很容易转换为C#2.0如果有必要...)

var grouped = new SortedDictionary<DateTime, List<TestClass>>(); 
foreach (TestClass entry in testList) { 
    DateTime date = entry.SomeTime.Date; 
    if (!grouped.ContainsKey(date)) { 
    grouped[date] = new List<TestClass>(); 
    } 
    grouped[date].Add(entry); 
} 

foreach (KeyValuePair<DateTime, List<TestClass>> pair in testList) { 
    Console.WriteLine("{0}: ", pair.Key); 
    Console.WriteLine(BuildSummaryLine(pair.Value)); 
} 
0

不管你如何生成的报表输出,如果你打算做这个经常在你的应用考虑组建一个报告界面,并实现类为这个接口来定位逻辑用于创建在一个地方的报告,而不是代码分散到在你的应用中创建报告。根据我的经验,应用程序通常具有(或增加)的多份报告,最终,多种格式的要求。

如果您只有一份报告,请不要担心,直到您编写第二份报告,,然后才开始制作报告架构,以便于扩展和维护。

例如(使用@Marc Gravell的代码):

public interface IReport 
{ 
    string GetTextReportDocument(); 
    byte[] GetPDFReportDocument(); // needing this triggers the development of interface 
} 

public class SalesReport : IReport 
{ 
    public void AddSale(Sale newSale) 
    { 
     this.Sales.Add(newSale); // or however you implement it 
    } 

    public string GetTextReportDocument() 
    { 
     StringBuilder reportBuilder = new StringBuilder(); 
     var groups = from row in this.Sales 
        group row by row.SomeTime.Date; 
     foreach (var group in groups.OrderBy(group => group.Key)) 
     {    
      reportBuilder.AppendLine(group.Key); 
      foreach(var item in group.OrderBy(item => item.SomePrice))    
      { 
      reportBuilder.AppendLine(item.SomePrice); 
      } 
      reportBuilder.AppendLine("Total" + group.Sum(x=>x.SomePrice)); 
     } 

     return reportBuilder.ToString(); 
    } 

    public byte[] GetPDFReportDocument() 
    { 
     return PDFReporter.GenerateDocumentFromXML(this.ConvertSalesToXML()); 
    } 

...剩下的就留给读者做练习...