Bala R
Bala R

Reputation: 108937

Combining two simple related linq queries

I have two queries and i'm using the result of the first one in the second one like this

 var temp  = (ObjectTable.Where(o => o.Category == "Y"));
 var anonymousObjList = temp.Select(o => new {o, IsMax = (o.Value == temp.Max(x => x.Value))});

Is there a way to combine these into one query?

EDIT: I cannot just chain them directly because I'm using temp.Max() in the second query.

Upvotes: 1

Views: 472

Answers (3)

Kirk Broadhurst
Kirk Broadhurst

Reputation: 28698

You can do it in one statement using query syntax, using the let keyword. It only evaluates the 'max' once, so it just like the three separate statements, just in one line.

var anonymousObjList = from o in ObjectTable
                       where o.Category == "Y"
                       let max = ObjectTable.Max(m => m.Value)
                       select new { o, IsMax = (o.Value == max) };

This is the only time I ever use query syntax. You can't do this using method syntax!

edit: ReSharper suggests

var anonymousObjList = ObjectTable.Where(o => o.Category == "Y")
    .Select(o => new {o, max = ObjectTable.Max(m => m.Value)})
    .Select(@t => new {@t.o, IsMax = (@t.o.Value == @t.max)});

however this is not optimal. The first Select is projecting a max Property for each item in ObjectTable - the Max function will be evaluated for every item. If you use query syntax it's only evaluated once.

Again, you can only do this with query syntax. I'm not fan of query syntax but this makes it worthwhile, and is the only case in which I use it. ReSharper is wrong.

Upvotes: 1

Chris Pitman
Chris Pitman

Reputation: 13104

Possibly the most straightfirward refactoring is to replace all instances of "temp" with the value of temp. Since it appears that this value is immutable, the refactoring should be valid (yet ugly):

var anonymousObjList = ObjectTable.Where(o => o.Category == "Y")
    .Select(o => new {o, IsMax = (o.Value == ObjectTable.Where(o => o.Category == "Y").Max(x => x.Value))});

As has already been pointed out, this query really has no advantages over the original, since queries use deffered execution and can be built up. I would actually suggest splitting the query even more:

var temp  = (ObjectTable.Where(o => o.Category == "Y")); 
var maxValue = temp.Max(x => x.Value);    
var anonymousObjList = temp.Select(o => new {o, IsMax = (o.Value == maxValue)});

This is better than the original because every time "Max" is called causes another iteration over the entire dataset. Since it is being called in the Select of the original, Max was being called n times. That makes the original O(n^2)!

Upvotes: 1

Paul
Paul

Reputation: 564

Why? it would be clearer (and more efficient) to make it three:

var temp  = (ObjectTable.Where(o => o.Category == "Y"));
int max = temp.Max(x => x.Value);
var anonymousObjList = temp.Select(o => new {o, IsMax = (o.Value == max)});

Upvotes: 5

Related Questions