3

I have searched but have not found my answer. Disclaimer: I am brand new to C# but I have a task at work to create the following program: Read from existing Log Files, Parse them by Tab, Limit the results to a specific status (Process E-mail), Group by Division (i.e. Investment Bank), then calculate statistics for amount of conversions of emails by division, and print to a new log file.

Wanted to give a bit of background on the program itself prior to asking the question. I am currently at the point where I would like to group by Division, and cant figure out how to do it.

EDIT: original data:

Status          Division      Time          Run Time    Zip Files   Conversions Returned Files  Total E-Mails   
Process E-mail  Investment Bank  12:00 AM   42.8596599  1               0               1             1 
End Processing                   12:05 AM   44.0945784  0               0               0             0 
Process E-mail  Investment Bank  12:10 AM   42.7193253  2               1               0             1 
Process E-mail  Treasury         12:15 AM   4.6563394   1               0               2             2

Here is the code that I have up to this point:

static void Main()
{
    {

        List<string> list = new List<string>();
        using (StreamReader reader = new StreamReader(Settings.LogPath + "2012-3-10.log"))
        {
            string line;
            int i = 0;
            while ((line = reader.ReadLine()) != null)
            {
                list.Add(line);
                i++;

                string[] split = line.Split('\t');

                string processing = split[0];

                    if(processing.StartsWith("Process"))
                    {
                        string division = split[1];
                        int zipFiles;
                        int.TryParse(split[4], out zipFiles);
                        int conversions;
                        int.TryParse(split[5], out conversions);
                        int returnedFiles;
                        int.TryParse(split[5], out returnedFiles);
                        int totalEmails;
                        int.TryParse(split[5], out totalEmails);

So I have the program to the point where it will spit out something to the console like this:

Investment Bank
1
0
1
1

Treasury
1
0
2
2

Investment Bank
2
1
0
1

What I am looking to do now, is group by "Investment Bank", "Treasury", etc and then be able to calculate the totals.

The final log file will look like this:

Division         Zip Files Conversions Returned Files Total E-mails
Investment Bank   3            1             1              2
Treasury          1            0             2              2
ekad
  • 14,436
  • 26
  • 44
  • 46
Cameron Balch
  • 189
  • 1
  • 10
  • and what is your original data? – Johnny_D Apr 04 '12 at 13:57
  • why not just use a switch case on the stream reader to separate the data based on your Criteria (whatever would specify Treasury vs. Investment Bank, etc.). I would personally probably capture each division as it's own object and wrap that in a parent object to reference. IE Class Division has a List and List – CBRRacer Apr 04 '12 at 14:18
  • @Johnny_D - added the original data set, mind you this is only a very small view of the log file, there are many more divisions, etc – Cameron Balch Apr 04 '12 at 14:27

2 Answers2

1

The following code does what you need:

string filename = @"D:\myfile.log";
var statistics = File.ReadLines(filename)
    .Where(line => line.StartsWith("Process"))
    .Select(line => line.Split('\t'))
    .GroupBy(items => items[1])
    .Select(g =>
            new 
                {
                    Division = g.Key,
                    ZipFiles = g.Sum(i => Int32.Parse(i[2])),
                    Conversions = g.Sum(i => Int32.Parse(i[3])),
                    ReturnedFiles = g.Sum(i => Int32.Parse(i[4])),
                    TotalEmails = g.Sum(i => Int32.Parse(i[5]))
                });

Console.Out.WriteLine("Division\tZip Files\tConversions\tReturned Files\tTotal E-mails");
statistics
   .ToList()
   .ForEach(d => Console.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}", 
           d.Division, 
           d.ZipFiles, 
           d.Conversions, 
           d.ReturnedFiles,  
           d.TotalEmails));

It could be even shorter (though less clear) if not to mess with anonymous classes but work with arrays instead. Let me know if you are intrested in such code.

the_joric
  • 11,986
  • 6
  • 36
  • 57
  • Wow thank you so much, this is EXACTLY what I am looking for. Now to go through this and try to understand what the logic is behind it ;) – Cameron Balch Apr 04 '12 at 14:41
  • no this is great, like I said earlier my boss kind of just threw me on this project so I am learning C# and pretty much learning programming while I go. – Cameron Balch Apr 04 '12 at 14:47
  • I've used C# (though not as much LINQ) for quite a while now. I had no idea GroupBy could be used so powerfully. This is a great example of the power. – Kevin Anderson Apr 04 '12 at 15:38
  • Hey @the_joric, quick question for you. With regards to the conversion to integers (Int32.Parse)...is there a way to use TryParse so that the exceptions are handled automatically? Thanks in advance – Cameron Balch Apr 05 '12 at 15:14
  • Sure, you can create a method `ToInt32(string s) {int i; Int32.TryParse(s, out i); return i;}` and replace all Sum stuff to `g.Sum(i => ToInt23(i[2])` – the_joric Apr 06 '12 at 09:13
  • @the_joric - I am having some difficulty with another portion of the program I am trying to build. Is it best to just ask another question on here or would you mind potentially exchanging an email for some help. Thanks in advance! – Cameron Balch Apr 23 '12 at 14:20
  • feel free to send email to [kalinets at gmail dot com] – the_joric Apr 24 '12 at 12:18
0

I would build a class then to handles this.

something like

public class xxxx
{
    Public string Division {get;set}
    Public Dictionary<string,int> something{get;set;}
}

Then you could just encapsulate them with

List<xxx> Divisions;

Not sure if this is optimal, but it would work.

Jeremy
  • 58
  • 6
  • thanks for the response, let me look into this...again, I am extremely new to C# so I would have to do some research on how to get this done. Can you maybe provide an example using my data rather than xxx and something, etc? That would be extremely helpful. Thanks! – Cameron Balch Apr 04 '12 at 14:30