Reputation: 13
From my xml testreport I need to do a weighted sum of the defects, group the sums per project and for all dates. Finally I need some list I can display in graphs on a web-site. I’m stuck with the last bit to extract the lists.
I have attached the xml and codesnip of how far I got so far.
namespace LinqTest
{
class Program
{
static void Main(string[] args)
{
int WDCFact_1 = 5;
int WDCFact_2 = 10;
int WDCFact_3 = 20;
XDocument test = XDocument.Load(@"..\..\Helpers\XMLFile1.xml");
var selected = from p in test.Descendants("Sample")
group p by p.Element("Date").Value into gDate
from projects in
(from proj in gDate
group proj by proj.Element("Project").Value)
select new
{
Date = DateTime.Parse(gDate.Key),
proj = projects.Key,
WDC = projects.Sum(t => (t.Element("Severity3") == null || t.Element("Severity3").Value == "") ? 0 : (int)t.Element("Severity3") * WDCFact_3) +
projects.Sum(t => (t.Element("Severity1") == null || t.Element("Severity1").Value == "") ? 0 : (int)t.Element("Severity1") * WDCFact_1) +
projects.Sum(t => (t.Element("Severity2") == null || t.Element("Severity2").Value == "") ? 0 : (int)t.Element("Severity2") * WDCFact_2)
};
var allprj = (from p in selected
select p.proj).Distinct().ToList();
var prj = from p in selected.GroupBy(d => d.Date)
select new
{
_d = p.LastOrDefault()
};
string mybreakpoint = "";
}
}
}
Expected result:
List<DateTime> Dates = {12-02-2014, 13-02-2014, 14-02-2014, 15-02-2014}
List<int> WDC_prj1 = {45, 150, 65, 85}
List<int> WDC_prj2 = {110, 110, 115, 260}
List<int> WDC_prj3 = {250, 0, 235, 245}
List<int> WDC_prj4 = {170, 60, 250, 240}
List<int> WDC_prj5 = {0, 205, 0, 15}
XML input:
<HistoricalData xmlns:xsi="http:www.w3.org/2001/XMLSchema-instance">
<Sample>
<Date>12-02-2013 00:00</Date>
<Project>Prj1</Project>
<Business_Line>BL1</Business_Line>
<Severity1>9</Severity1>
</Sample>
<Sample>
<Date>12-02-2013 00:00</Date>
<Project>Prj2</Project>
<Business_Line>BL1</Business_Line>
<Severity1>8</Severity1>
<Severity2>1</Severity2>
<Severity3>3</Severity3>
</Sample>
<Sample>
<Date>12-02-2013 00:00</Date>
<Project>Prj3</Project>
<Business_Line>BL1</Business_Line>
<Severity1>8</Severity1>
<Severity2>3</Severity2>
<Severity3>9</Severity3>
</Sample>
<Sample>
<Date>12-02-2013 00:00</Date>
<Project>Prj4</Project>
<Business_Line>BL2</Business_Line>
<Severity1>2</Severity1>
<Severity2>0</Severity2>
<Severity3>8</Severity3>
</Sample>
<Sample>
<Date>13-02-2013 00:00</Date>
<Project>Prj1</Project>
<Business_Line>BL1</Business_Line>
<Severity1>6</Severity1>
<Severity2>8</Severity2>
<Severity3>2</Severity3>
</Sample>
<Sample>
<Date>13-02-2013 00:00</Date>
<Project>Prj2</Project>
<Business_Line>BL1</Business_Line>
<Severity1>8</Severity1>
<Severity2>3</Severity2>
<Severity3>2</Severity3>
</Sample>
<Sample>
<Date>13-02-2013 00:00</Date>
<Project>Prj3</Project>
<Business_Line>BL1</Business_Line>
</Sample>
<Sample>
<Date>13-02-2013 00:00</Date>
<Project>Prj4</Project>
<Business_Line>BL2</Business_Line>
<Severity1>0</Severity1>
<Severity2>6</Severity2>
<Severity3>0</Severity3>
</Sample>
<Sample>
<Date>13-02-2013 00:00</Date>
<Project>Prj5</Project>
<Business_Line>BL1</Business_Line>
<Severity1>1</Severity1>
<Severity2>6</Severity2>
<Severity3>7</Severity3>
</Sample>
<Sample>
<Date>14-02-2013 00:00</Date>
<Project>Prj1</Project>
<Business_Line>BL1</Business_Line>
<Severity1>3</Severity1>
<Severity2>1</Severity2>
<Severity3>2</Severity3>
</Sample>
<Sample>
<Date>14-02-2013 00:00</Date>
<Project>Prj2</Project>
<Business_Line>BL1</Business_Line>
<Severity1>7</Severity1>
<Severity2>0</Severity2>
<Severity3>4</Severity3>
</Sample>
<Sample>
<Date>14-02-2013 00:00</Date>
<Project>Prj3</Project>
<Business_Line>BL1</Business_Line>
<Severity1>7</Severity1>
<Severity2>4</Severity2>
<Severity3>8</Severity3>
</Sample>
<Sample>
<Date>14-02-2013 00:00</Date>
<Project>Prj4</Project>
<Business_Line>BL2</Business_Line>
<Severity1>8</Severity1>
<Severity2>5</Severity2>
<Severity3>8</Severity3>
</Sample>
<Sample>
<Date>15-02-2013 00:00</Date>
<Project>Prj1</Project>
<Business_Line>BL1</Business_Line>
<Severity1>1</Severity1>
<Severity2>4</Severity2>
<Severity3>2</Severity3>
</Sample>
<Sample>
<Date>15-02-2013 00:00</Date>
<Project>Prj2</Project>
<Business_Line>BL1</Business_Line>
<Severity1>8</Severity1>
<Severity2>6</Severity2>
<Severity3>8</Severity3>
</Sample>
<Sample>
<Date>15-02-2013 00:00</Date>
<Project>Prj3</Project>
<Business_Line>BL1</Business_Line>
<Severity1>1</Severity1>
<Severity2>8</Severity2>
<Severity3>8</Severity3>
</Sample>
<Sample>
<Date>15-02-2013 00:00</Date>
<Project>Prj4</Project>
<Business_Line>BL2</Business_Line>
<Severity1>8</Severity1>
<Severity2>8</Severity2>
<Severity3>6</Severity3>
</Sample>
<Sample>
<Date>15-02-2013 00:00</Date>
<Project>Prj5</Project>
<Business_Line>BL1</Business_Line>
<Severity1>3</Severity1>
<Severity2>0</Severity2>
<Severity3>0</Severity3>
</Sample>
</HistoricalData>
Upvotes: 1
Views: 114
Reputation: 8404
This would do the trick:
List<DateTime> Dates = selected.Select(each => each.Date).Distinct().ToList();
List<int> WDC_prj1 = selected
.Where(sample => sample.proj == "Prj1")
.Select(sample => sample.WDC).ToList();
List<int> WDC_prj2 = selected
.Where(sample => sample.proj == "Prj2")
.Select(sample => sample.WDC).ToList();
// etc.
Note that 2014 dates (which you gave as your expect result) don't actually exist in your sample (it's all 2013 in there), but I assume it was a typo and all you wanted was a list of distinct dates.
EDIT:
Okay, I just noticed that if a value for PrjX
is skipped, you want a 0 instead.
My code would give you WDC_prj5 = {205, 15}
, while you actually want {0, 205, 0, 15}
(because no Prj5
comes after the first four samples).
We can fullfill this requirement by iterating the samples in a loop and keeping track of which Prjs
were missing. Then - every time we come across Prj1
again - we substitute them with zeroes.
For example:
var values = Enumerable.Range(1, 5).ToDictionary(n => n, n => new List<int>());
bool firstIteration = true;
var visited = new BitArray(5, false);
foreach(var sample in selected)
{
int number = Int32.Parse(sample.proj.Last().ToString());
visited[number - 1] = true;
if (number == 1 && !firstIteration)
{
for (int i = 0; i < 5; i++)
{
if (!visited[i])
values[i + 1].Add(0);
}
visited.SetAll(false);
}
values[number].Add(sample.WDC);
firstIteration = false;
}
And now just:
List<int> WDC_prj1 = values[1];
List<int> WDC_prj2 = values[2];
Etc.
Or, if you think LINQ is cool and performance considerations don't scare you, you could throw the BitArray
away:
foreach(var sample in selected)
{
int number = Int32.Parse(sample.proj.Last().ToString());
if (number == 1)
{
// we just started a new cycle...
int expectedNumberOfValues = values.Values.Max(list => list.Count);
values = values.ToDictionary(
kvp => kvp.Key,
kvp => kvp.Value.Concat(Enumerable.Repeat(0, expectedNumberOfValues - kvp.Value.Count)).ToList());
}
values[number].Add(sample.WDC);
}
Collecting the results remains the same:
List<int> WDC_prj1 = values[1];
List<int> WDC_prj2 = values[2];
PS.
On a side note, beware of DateTime.Parse
.
It's culture sensitive and it can crash on another version of Windows.
For example on my computer it crashed trying to parse 13-02-2013 00:00
(and it parsed 12-02-2013
incorrectly as 2nd of December).
In this case you'd be better off using DateTime.ParseExact(d, "dd-MM-yyyy HH:mm", CultureInfo.InvariantCulture)
instead. Even if it's only supposed to work on your PC - I have no way of knowing - it's still a good habit to have.
Upvotes: 2