2

I have a list of objects with a StartDate property but I filter it out to just dates.

So ListOfDates contains 2016-04-05, 2016-04-07 or more.

I have another list of objects with RequestDate that has dates that range from 2014 to 2016.

How can I write a LINQ with a condition where RequestDate is greater than any of the dates in ListOfDates? I'm looking for something like Contains but works for comparisons.

Jack
  • 5,680
  • 10
  • 49
  • 74

3 Answers3

5

See code below:

var objects = RequestObjects.Where(r => r.RequestDate > ListOfDates.Max());
Riad Baghbanli
  • 3,105
  • 1
  • 12
  • 20
  • 3
    Calling Max() in advance is more efficient. – Toxantron Apr 05 '16 at 23:05
  • 1
    Compiler will do that for you (optimization step), no need to explicitly write it out. – Riad Baghbanli Apr 05 '16 at 23:18
  • Good to know. Wasn't sure the JIT is smart enough. – Toxantron Apr 05 '16 at 23:21
  • 2
    @rbaghbanli: I'm pretty sure that the compiler will not optimize this away with Linq, and Max() will get called on all iterations. Here's a Jon Skeet comment that seems to confirm this, and states that this pattern is indeed O(n^2): http://stackoverflow.com/a/1101979/81179 (first bullet point, not everyone may be able to see the deleted answer he linked to). – ChristopheD Apr 06 '16 at 00:32
  • @ChristopheD , in your link the pattern described is for finding an element with property at max, Jon refers to MaxBy from MoreLINQ as the way to solve that problem with (n) instead of (n^2). In the case of code shown here, enumerations are different (unlike the example in the link), so the value from the linq statement on the first enumeration will be kept in register for comparison while enumerating the second. This is one of the basic performance optimizations. – Riad Baghbanli Apr 06 '16 at 17:19
  • @rbaghbanli: I beg to differ. John skeet says "previous accepted answer which finds the maximum value on every iteration (making it O(n^2))". When you look at the previous accepted answer he is referring to, that has the following code snippet: `listOfDimensionPairs.Where(dp => dp.Height == listOfDimensionPairs.Max(h => h.Height))`, which is exactly what you are doing (calling Max() in a Where()). – ChristopheD Apr 06 '16 at 20:12
  • @ChristopheD, again, listOfDimensionPairs.Where(dp => dp.Height == listOfDimensionPairs.Max(h => h.Height)), the same list (listOfDimensionPairs) gets enumerated and compiler does not know if it is ok to optimize it. It will indeed end up as n^2. In the code shown Max is applied to the list of dates, where as outer iteration goes over the list of objects. In this case compiler will optimize, as it is fair to assume constance of the result of Max iteration. – Riad Baghbanli Apr 06 '16 at 21:16
  • @rbaghbanli: I agree it's a bad example I linked to (different situation). Sorry for that. However, constant folding in C# only happens (I think) at compile time, and at that time, ListOfDates.Max() can not be known unless ListOfDates is constant too. Perhaps the compiler moves the expression 'out' of the lambda, but I would be a bit surprised that it did that. JIT might interfere. After all of this, I'm not too sure anymore. So I'll ask a new Stackoverflow question :-). – ChristopheD Apr 06 '16 at 23:41
  • @ChristopheD, I am looking for an article on LINQ and compiler optimization on LINQ statements to share. That question did come up before, not sure how to construct the search phrase to find the question or an original article. – Riad Baghbanli Apr 07 '16 at 17:48
  • @rbaghbanli: Let me know if you find anything. In the mean time, I've opened this question: http://stackoverflow.com/questions/36464287/can-the-c-sharp-compiler-or-jit-optimize-away-a-method-call-in-a-lambda-expressi. The consensus in the comments is currently that the compiler can't optimize this away. – ChristopheD Apr 07 '16 at 17:51
4

Assuming you're comparing with a single date (I'm not completely clear on that based on your question), you are looking for Any:

bool answer = ListOfDates.Any(date => RequestDate > date);
Blorgbeard
  • 101,031
  • 48
  • 228
  • 272
4

I suppose this is what you are looking for.

request.Where(r => ListOfDates.All(d => d < r.RequestDate))

It would however be faster to get the maximum first and then filter:

var max = ListOfDates.Max();
var match = requests.Where(r => r.RequestDate > max)
Toxantron
  • 2,218
  • 12
  • 23