2016-05-04 27 views
0

Ich habe diese Schleife, die diese IEnumerables eins nach dem anderen erstellt, ich möchte in der Lage sein, dies zu optimieren, so dass es die IEnumerables auf einmal in einem IEnumerable statt einer Liste von ihnen als den Anruf tätigen und bauen kann Schleife hat zu tun. Der Code gruppiert FilteredCases (Fälle verschiedener Baumarten in einem Jahr) nach Monat und berechnet den Prozentsatz der Bäume für diesen Monat im Vergleich zum gesamten Jahr. Mein Problem ist, dass ich das für jedes Jahr separat mache und dies hoffentlich in einem LINQ-Aufruf tun würde, indem ich hoffentlich die richtigen Daten gruppiere.Wie kann diese Schleife in eine linq-Abfrage optimiert werden, um den Schleifenaufruf vollständig zu entfernen?

Hier ist der Code:

 var seriesDataLineList = new List<IEnumerable<SeriesDataPointArray>>(); 

     foreach (var tree in trees) 
     { 
      IEnumerable<SeriesDataPointArray> seriesDataLine = months.Select(month => new SeriesDataPointArray() 
      { 
       X = month.LookupMonthName, 
       Y = new object[] { Math.Round(FilteredCases.Count(fc => fc.LookupTreeId == tree.LookupTreeId && fc.LookupMonthId == month.LookupMonthId)/(double)FilteredCases.Count(fc => fc.LookupTreeId == tree.LookupTreeId) * 100, 0) } 
      }); 

      seriesDataLineList.Add(seriesDataLine); 
     } 

Mein Versuch, dies mit LINQ tun:

var test = from fc in FilteredCases 
      group fc by new { fc.Tree, fc.Month } 
      into casesGrouped 
      orderby casesGrouped.Key.Tree 
      select new { casesGrouped.Key.Tree, casesGrouped.Key.Month, count = casesGrouped.Count() }; 

Aber ich bin nicht sicher, wie diese zu bekommen in eine IEnuerable<SeriesDataPointArray>

Antwort

0

Was haben Sie Oben ist eine Mischung aus Loops und Linq, die verwirrend sein kann, weil Sie iterativ mit Set-based Logic mischen. Wenn Sie den Code als "just loops" erweitern, ist es möglicherweise einfacher, sie in linq zu übersetzen.

Da alle Schleifen

 var seriesDataLineList = new List<SeriesDataPointArray>(); 
     foreach (var tree in trees) 
     { 
      foreach (var month in months) 
      { 
       var seriesDataLine = new SeriesDataPointArray() 
       { 
        X = month.LookupMonthName, 
        Y = new double[] { Math.Round(FilteredCases.Count(fc => fc.LookupTreeId == tree.LookupTreeId && fc.LookupMonthId == month.LookupMonthId)/(double)FilteredCases.Count(fc => fc.LookupTreeId == tree.LookupTreeId) * 100, 0) } 
       }; 
       seriesDataLineList.Add(seriesDataLine); 
      }; 
     } 

Sobald Sie den Code in allen Schleifen erhalten, zu Linq Umwandlung recht geradlinig ist. Verschachtelte Schleifen sind funktionell äquivalent zu einem kartesischen Produkt, das syntaktisch in linq durch mehrere unkorrelierte for-Anweisungen erreicht werden kann.

 var results = from tree in trees 
         from month in months 
         select new SeriesDataPointArray() 
         { 
          X = month.LookupMonthName, 
          Y = new double[] { Math.Round(FilteredCases.Count(fc => fc.LookupTreeId == tree.LookupTreeId && fc.LookupMonthId == month.LookupMonthId)/(double)FilteredCases.Count(fc => fc.LookupTreeId == tree.LookupTreeId) * 100, 0) } 
         }; 

Oder in Lambda, mehrere verschachtelte Select-Anweisungen. Sie brauchen irgendwo eine SelectMany(), um die verschachtelten Sammlungen zu reduzieren.

 var results = trees.Select(tree => 
      months.Select(month => 
       new SeriesDataPointArray() 
       { 
        X = month.LookupMonthName, 
        Y = new double[] { Math.Round(FilteredCases.Count(fc => fc.LookupTreeId == tree.LookupTreeId && fc.LookupMonthId == month.LookupMonthId)/(double)FilteredCases.Count(fc => fc.LookupTreeId == tree.LookupTreeId) * 100, 0) } 
       } 
      ) 
     ).SelectMany(x => x);