Jerry Nixon
Jerry Nixon

Reputation: 31823

Lambda Max and Max and Max

Quick and probably easy Lambda question:

I have a restaurant with reviews. I want to query for the one with the:

Something like this:

var _Result = AllRestaurants
    .Max(x => x.AverageRating)
    .AndMax(x => x.ReviewCount)
    .AndMax(x => x.NewestReviewDate)
    .AndMin(x => x.DistanceAway);

Now, I know that is pseudo code. But it describes it perfectly!

Of course, in multiple statements, this is simple.

Just wondering if this is possible in one statement without killing the readability.

Thank you in advance. I know some of you love the query questions!

Upvotes: 3

Views: 7030

Answers (5)

Richard
Richard

Reputation: 30628

Perhaps this would do?

var bestRestaurant = AllRestaurants
    .OrderByDescending(r => r.AverageRating)
    .ThenByDescending(r => r.ReviewCount)
    .ThenByDescending(r => r.NewestReviewCount)
    .ThenBy(r => r.DistanceAway)
    .FirstOrDefault();

You'd need to change the order of the statements to reflect which is the most important.

Upvotes: 6

Steve Wortham
Steve Wortham

Reputation: 22230

If I'm understanding your question, I think the best approach is going to be writing individual statements as you mention...

var HighestRating = AllRestaurants.Max(x => x.AverageRating);
var HighestReviewCount = AllRestaurants.Max(x => x.ReviewCount);
var LatestReviewDate = AllRestaurants.Max(x => x.NewestReviewDate);
var ShortestDistanceAway = AllRestaurants.Min(x => x.DistanceAway);

Retrieving various maxes and mins from a single Linq query would get pretty messy and I'm not sure there'd be any advantage with efficiency, either.

Upvotes: 0

Brett Forsgren - MSFT
Brett Forsgren - MSFT

Reputation: 832

An alternative to having some weighted heuristic is to order by AverageRating, then ReviewCount, then ...

Something like this should work:

var _Result = AllRestaurants
    .OrderByDescending(x => x.AverageRating)
    .ThenByDescending(x => x.ReviewCount)
    .ThenByDescending(x => x.NewestReviewDate)
    .ThenByDescending(x => x.DistanceAway);
    // using *Descending so you get the higer-valued ones first

Upvotes: 1

Andrew Gray
Andrew Gray

Reputation: 3790

Consider something like this...

List<RestaurantRecord> _Restaurants;

public RestaurantRecord Best()
{
    return _Restaurants.Where(
               x =>
                   x.AverageRating >= _BestRating &&
                   x.ReviewCount >= _MinReviews &&
                   x.Distance <= _MaxDistance)
                       .GetFirstOrDefault();
}

That being said, using a lambda in this case will have maintainability consequences down the road. It would be a good idea to refactor this, such that if other criteria appear in the future (e.g.: smartphone access? Cuisine type?), your app can be more easily modified to adapt to those.

On that note, a slightly better implementation might be something like:

public RestaurantRecord Best()
{
    IQueryable temp = _Restaurants.Clone();

    temp = temp.Where( x => x.AverageRating >= _BestRating );
    temp = temp.Where( x => x.ReviewCount >= _MinReviews );
    // ...snip...

    return temp.GetFirstOrDefault();
}

I hope this sets you on the right track. :)

Upvotes: 0

IngisKahn
IngisKahn

Reputation: 869

You can't have multiple maxes or mins, that doesn't make sense. You'll need some kind of heuristic like:

   .Max(x => x.AverageRating * x.ReviewCount - x.DaysSinceLastReview - x.DistanceAway)

Upvotes: 6

Related Questions