2016-05-26 6 views
5

Ho una lista dei bug MyBugList creata usando la seguente classequery LINQ su un elenco di oggetti per ottenere distribuzione basata su più campi

internal class BugDetails 
{ 
    public int Id { get; set; } 
    public string State { get; set; } 
    public string Severity { get; set; } 
} 

ho voluto raggruppare questi insetti a base di State e Severity. Ho usato il seguente codice per realizzarlo.

var BugListGroup = (from bug in MyBugList 
          group bug by new 
          { 
           bug.State, 
           bug.Severity 
          } into grp 
          select new 
          { 
           BugState = grp.Key.State, 
           BugSeverity = grp.Key.Severity, 
           BugCount = grp.Count() 
          }).OrderBy(x=> x.BugState).ToList(); 

Questa query LINQ mi dà output come il seguente

Closed  Critical 40 
Active  Critical 167 
Closed  Medium  819 
Closed  Low   323 
Resolved Medium  61 
Resolved Low   11 
Closed  High  132 
Active  Low   17 
Active  Medium  88 
Active  High  38 
Resolved High  4 
Resolved Critical 22 
Deferred High  11 

Tuttavia mi piacerebbe ottenere un output come di seguito

  Critical High Medium Total 
Closed  3   4  5  12 
Active  5   4  5  14 
Resolved 6   4  5  15 
Deferred 1   4  5  10 
Total  15   16  20  51 

E 'possibile ottenere questo tramite una query LINQ su MyBugList o su BugListGroup

Vorrei ottenere l'output come elenco in modo che possa essere possibile creare una griglia di dati come .

Nota: i valori dello Stato e la gravità sono dinamici e non possono essere codificati duro

Qui di seguito è la mia realizzazione con l'aiuto di risposta fornito da Dmitriy Zapevalov

private void button1_Click(object sender, EventArgs e) 
{ 
    var grouped = MyBugList.GroupBy(b => b.State).Select(stateGrp => stateGrp.GroupBy(b => b.Severity)); 

    //Setting DataGrid properties 
    dataGridBug.Rows.Clear(); 
    dataGridBug.Columns.Clear(); 
    dataGridBug.DefaultCellStyle.NullValue = "0"; 
    dataGridBug.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter; 

    //Declaring DataGrid Styles 
    var gridBackColor = Color.AliceBlue; 
    var gridFontStyle = new Font(Font, FontStyle.Bold | FontStyle.Italic); 

    //Declaring column and row Ids 
    const string stateColumnId = "State"; 
    const string totalColumnId = "Total"; 
    const string totalRowId = "Total"; 

    //Adding first column 
    dataGridBug.Columns.Add(stateColumnId, stateColumnId); 
    dataGridBug.Columns[0].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft; 

    //Adding other columns 
    foreach (var strSeverity in MyBugList.Select(b => b.Severity).Distinct()) 
    { 
     dataGridBug.Columns.Add(strSeverity, strSeverity); 
    } 

    //Adding Total Column 
    var totColPos = dataGridBug.Columns.Add(totalColumnId, totalColumnId); 
    var totCol = dataGridBug.Columns[totColPos]; 

    //Adding data to grid 
    foreach (var state in grouped) 
    { 
     var nRow = dataGridBug.Rows.Add(); 
     var severities = state as IList<IGrouping<string, BugDetails>> ?? state.ToList(); 
     dataGridBug.Rows[nRow].Cells[0].Value = severities.First().First().State; 
     var sevCount = 0; 
     foreach (var severity in severities) 
     { 
      dataGridBug.Rows[nRow].Cells[severity.Key].Value = severity.Count(); 
      sevCount += severity.Count(); 
     } 
     dataGridBug.Rows[nRow].Cells[totalColumnId].Value = sevCount; 
    } 


    //Adding total row 
    var totRowPos = dataGridBug.Rows.Add(totalRowId); 
    var totRow = dataGridBug.Rows[totRowPos]; 

    //Adding data to total row 
    for (var c = 1; c < dataGridBug.ColumnCount; c++) 
    { 
     var sum = 0; 
     for (var i = 0; i < dataGridBug.Rows.Count; ++i) 
     { 
      sum += Convert.ToInt32(dataGridBug.Rows[i].Cells[c].Value); 
     } 
     dataGridBug.Rows[totRowPos].Cells[c].Value = sum; 
    } 

    //Styling total column 
    totCol.DefaultCellStyle.BackColor = gridBackColor; 
    totCol.DefaultCellStyle.Font = gridFontStyle; 

    //Styling total row 
    totRow.DefaultCellStyle.BackColor = gridBackColor; 
    totRow.DefaultCellStyle.Font = gridFontStyle; 
} 


uscita nella griglia di dati sarà simile a

DataGrid Output

risposta

1

ho fatto doppio raggruppamento:

class Program 
{ 
    internal class BugDetails 
    { 
     public int Id { get; set; } 
     public string State { get; set; } 
     public string Severity { get; set; } 
    } 
    static void Main(string[] args) 
    { 
     var MyBugList = new BugDetails[] 
     { 
      new BugDetails() { Id = 1, State = "Active", Severity = "Critical" }, 
      new BugDetails() { Id = 1, State = "Closed", Severity = "Critical" }, 
      new BugDetails() { Id = 1, State = "Closed", Severity = "Critical" }, 
      new BugDetails() { Id = 1, State = "Closed", Severity = "Critical" }, 
      new BugDetails() { Id = 1, State = "Resolved", Severity = "Critical" }, 
      new BugDetails() { Id = 1, State = "Resolved", Severity = "Critical" }, 
      new BugDetails() { Id = 1, State = "Resolved", Severity = "Critical" }, 

      new BugDetails() { Id = 1, State = "Active", Severity = "Medium" }, 
      new BugDetails() { Id = 1, State = "Active", Severity = "Medium" }, 
      new BugDetails() { Id = 1, State = "Closed", Severity = "Medium" }, 
      new BugDetails() { Id = 1, State = "Closed", Severity = "Medium" }, 
      new BugDetails() { Id = 1, State = "Resolved", Severity = "Medium" }, 
      new BugDetails() { Id = 1, State = "Resolved", Severity = "Medium" }, 
      new BugDetails() { Id = 1, State = "Resolved", Severity = "Medium" }, 

      new BugDetails() { Id = 1, State = "Active", Severity = "High" }, 
      new BugDetails() { Id = 1, State = "Active", Severity = "High" }, 
      new BugDetails() { Id = 1, State = "Closed", Severity = "High" }, 
      new BugDetails() { Id = 1, State = "Closed", Severity = "High" }, 
      new BugDetails() { Id = 1, State = "Closed", Severity = "High" }, 
      new BugDetails() { Id = 1, State = "Closed", Severity = "High" }, 
      new BugDetails() { Id = 1, State = "Closed", Severity = "High" }, 
     }; 

     var grouped = MyBugList.GroupBy(b => b.State). 
      Select(stateGrp => stateGrp.GroupBy(b => b.Severity)); 

     foreach (var state in grouped) 
     { 
      Console.Write("{0}: ", state.First().First().State); 
      foreach (var severity in state) 
      { 
       Console.Write("{0}={1} ", severity.Key, severity.Count()); 
      } 
      Console.WriteLine(); 
     } 
    } 
} 

Uscita:

Active: Critical=1 Medium=2 High=2 
Closed: Critical=3 Medium=2 High=5 
Resolved: Critical=3 Medium=3 

Se si desidera visualizzare i dati con DataGridView In tal caso è possibile creare il tipo in modo dinamico con il proprio set di proprietà. Ma in questo modo è complicato. Il modo più semplice (e più prestazioni) è quello di riempire manualmente DataGridView:

private void button1_Click(object sender, EventArgs e) 
{ 
    var grouped = MyBugList.GroupBy(b => b.State). 
     Select(stateGrp => stateGrp.GroupBy(b => b.Severity)); 

    dataGridView1.Columns.Add("State", "State"); 
    foreach (var strSeverity in MyBugList.Select(b => b.Severity).Distinct()) 
     dataGridView1.Columns.Add(strSeverity, strSeverity); 

    foreach (var state in grouped) 
    { 
     int nRow = dataGridView1.Rows.Add(); 
     dataGridView1.Rows[nRow].Cells[0].Value = state.First().First().State; 
     foreach (var severity in state) 
     { 
      dataGridView1.Rows[nRow].Cells[severity.Key].Value = severity.Count(); 
     } 
    } 
} 

Il risultato: enter image description here

+0

Dove è possibile visualizzare i valori con hardcoded? Questo array 'test' è solo per l'output. Dovresti scrivere solo una parte partendo da 'var grouped =' –

+0

Oh, mi dispiace, per un rapido sguardo pensavo che tu avessi codificato duro. Darò un'occhiata e ti farò sapere – Ian

+0

Funziona bene, tuttavia voglio ottenere l'output come elenco in modo che possa essere inviato a un DataGrid. – Ian

3

È possibile eseguire questa operazione (è una soluzione dinamica, in cui non è necessario eseguire l'hardcode di alcunché). Details proprietà di BugModel classe contiene tutte le colonne come Critical, alta e così via:

public class BugModel 
{ 
    public string BugState { get; set; } 
    public Dictionary<string, int> Details { get; set; } 
    public int Total { get { return Details.Sum(x => x.Value); } } 
} 

Soluzione:

var result = (from bug in BugListGroup 
       group bug by bug.BugState into sub 
       select new BugModel 
       { 
        BugState = sub.Key, 
        Details = sub.GroupBy(x => x.BugSeverity) 
          .ToDictionary(x => x.Key, x => x.Sum(y => y.BugCount)) 
       }).ToList(); 
+0

questo è davvero buono, tuttavia voglio ottenere l'output come un elenco in modo che io possa fonte a un DataGrid. Quando faccio questo, ottengo le seguenti colonne BugState, Details e Total. La colonna Dettagli è mostrata come raccolta.Ho bisogno di un modo in cui la griglia mostri i dati come ho menzionato nella domanda. – Ian

+0

Vuoi ottenere il risultato, in cui tutte le righe avranno proprietà separate per ogni colonna, invece di una proprietà come elenco dinamico (dizionario) per tutte le colonne? In questo caso, sfortunatamente, dovresti inserire un hardcode, perché il tuo problema è il classico problema ** PIVOT **, dove, come sai, anche le colonne devono essere enumerate manualmente. Puoi provare a creare una classe in runtime con il set di proprietà necessario e quindi tramite reflection impostare i suoi valori di proprietà. –

Problemi correlati