This question already has an answer here:
- Is it possible to Pivot data using LINQ? 6 answers
I have the following class structure:
public class TaskLog
{
public DateTime LogDate { get; set; }
public string Robot { get; set; }
public string Task { get; set; }
public Enums.ProbeDataState State { get; set; }
public TaskLog()
{
}
}
I created a generic list as follows:
List<TaskLog> Logs;
My output:
Robot Date State
---------------------------------------------
aaa 8/5/2013 12:00:00 AM Task:1=fileDeltaFailed
aaa 8/5/2013 12:00:00 AM Task:2=fileDeltaFailed
aaa 8/5/2013 12:00:00 AM Task:4=fileDeltaFailed
bbb 8/5/2013 12:00:00 AM Task:1=fileDeltaFailed
bbb 8/5/2013 12:00:00 AM Task:2=fileDeltaFailed
bbb 8/5/2013 12:00:00 AM Task:4=fileDeltaFailed
However I would like to group the tasks and state as follows:
Tasks
Robot Date 1 2 4
aaa 8/5/2013 12:00:00 AM fileDeltaFailed fileDeltaFailed fileDeltaFailed
bbb 8/5/2013 12:00:00 AM fileDeltaFailed fileDeltaFailed fileDeltaFailed
I tried using the groupby with no luck, and quite stuck.
e.g.
var dataQuery = Logs.Where(w => w.LogDate >= start && w.LogDate <= finish).GroupBy(g => g.LogDate).Select(t => new
{
LogDate = t.Key,
Details = t.OrderBy(o => o.Robot)
}).ToList();
If I understand the question, you want a mapping of Task to State for each Robot. You could group by Robot and select a dictionary for each group:
Logs.GroupBy(t => t.Robot).Select(g => new {
Robot = g.Key,
TaskStates = g.ToDictionary(t => t.Task, t => t.State)
})
This assumes that task names are unique for each robot (ToDictionary
would throw an exception otherwise).
You could also add another level of grouping for dates:
Logs.GroupBy(t => t.LogDate).Select(g => new {
Date = g.Key,
Details = g.GroupBy(t => t.Robot).Select(g => new {
Robot = g.Key,
TaskStates = g.ToDictionary(t => t.Task, t => t.State)
}).ToList()
})
Note that the Details
property is essentially equivalent to my first example, the only difference being that it queries the outer grouping instead of the whole sequence. The result is a sequence of {Date, Details} where each "detail" is a list of {Robot, TaskStates}.
I haven't tested this, so let me know if there are any bugs I missed.
var result = Logs.GroupBy(x=> new {x.Robot, x.Date})
.Select(g=> {
var a = g.ToList();
return
new {
a[0].Robot,
a[0].Date,
Task1 = a[0].State,
Task2 = a[1].State,
Task4 = a[2].State
};
});
Suppose you have to define a fixed number of Tasks
and to make it safer, we can do something like this:
var result = Logs.GroupBy(x=> new {x.Robot, x.Date})
.Select(g=> {
var c = g.Count();
var a = g.ToList();
return
new {
a[0].Robot,
a[0].Date,
Task1 = a[0].State,
Task2 = c > 1 ? a[1].State : "",
Task4 = c > 2 ? a[2].State : ""
};
});
try this:
var newData = from w in Logs
where w.LogDate >= start && w.LogDate <= finish
group w by w.LogDate into g
select new
{
LogDate = g.Key,
Details = g.ToList().OrderBy(o => o.Robot)
};
The query newData
contains a list of objects with LogDate and Detais (List of tasks ordered by Robot).
来源:https://stackoverflow.com/questions/18238046/trying-to-pivot-data-using-linq