Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this LINQ Query too long?

Tags:

c#

linq

I'm new to LINQ, and don't want to over do it and make this code hard to maintain.

What do you think, is this LINQ Query too long?

IList<ListViewItem> data = runAnalysis.PassAnalyses.Cast<PassAnalysis>().
  Select(passAnalysis => passAnalysis.GetValue(PeakStatistics.PeakStatisticsProperty)).
  SelectMany(peakStatistics => peakStatistics.Statistics.
    Where(statisticsBase => statisticsBase.Name == statisticType).
    Select(statisticsBase => new ListViewItem {Content = statisticsBase})).ToList();
like image 593
mkocubinski Avatar asked Dec 04 '22 11:12

mkocubinski


1 Answers

I would say it's complicated due to nesting - but doesn't really need to be. Here's an example of a query which will give the same results (I think), but is simpler...

IList<ListViewItem> data = runAnalysis.PassAnalyses
      .Cast<PassAnalysis>()
      .Select(pass => pass.GetValue(PeakStatistics.PeakStatisticsProperty))
      .SelectMany(peakStats => peakStats.Statistics)
      .Where(statisticsBase => statisticsBase.Name == statisticType)
      .Select(statisticsBase => new ListViewItem {Content = statisticsBase})
      .ToList();

Without the nesting, it's easy to see how the transformation goes:

  • Start with PassAnalyses
  • Cast each item to a PassAnalysis
  • Select the PeakStatistics
  • From each element, select all the Statistics within it, and flatten this sequence
  • Filter any statistic with the wrong name
  • Convert each result into a ListViewItem
  • Convert the whole sequence into a list

At this point, it's easy to convert it into a query expression:

IList<ListViewItem> data =
   (from PassAnalysis pass in runAnalysis.PassAnalyses
    from statsBase in pass.GetValue(PeakStatistics.PeakStatisticsProperty)
                          .Statistics
    where statsBase.Name == statisticType
    select new ListViewItem { Content = statsBase })
   .ToList();

Note that I've elided the first Select and the SelectMany; you could use a let clause if you wanted. Also I've used an explicit type for the pass range variable, to make the compiler generate the Cast<PassAnalysis >() call.

This is slightly different to the original version, as it will use a different form of SelectMany which propagates the original pass value too, but the results will be the same.

Calling ToList() at the end is somewhat ugly as there's no query expression syntax for it... but you could use an intermediate variable for that:

var query = ...;
IList<ListViewItem> data = query.ToList();
like image 132
Jon Skeet Avatar answered Dec 06 '22 01:12

Jon Skeet