2012-06-11 4 views
3

Rapide et probablement facile Question Lambda:Lambda Max et Max et Max

J'ai un restaurant avec commentaires. Je veux interroger pour celui avec le:

  • Max (AverageRating)
  • Et Max (reviewCount)
  • Et Max (NewestReviewDate)
  • Et le Min (DistanceAway)

Quelque chose comme ceci:

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

Maintenant, je sais que c'est un pseudo code. Mais il le décrit parfaitement!

Bien sûr, dans plusieurs instructions, c'est simple.

Je me demandais simplement si cela est possible dans une instruction sans tuer la lisibilité.

Merci d'avance. Je sais que certains d'entre vous aiment les questions d'interrogation!

+1

La question est claire. Chacune des cinq requêtes que vous avez mentionnées peut renvoyer un restaurant différent. Cela n'a aucun sens de combiner les requêtes de cette manière. – Odrade

+4

Et que devrait contenir le résultat? Un restaurant unique qui a la meilleure combinaison de tous les critères, ou 4 restaurants différents, un pour chaque critère? Notez que vous devriez expliquer en détail, car chaque option devrait encore être clarifiée plus en détail. – Servy

Répondre

6

Vous ne pouvez pas avoir plusieurs maxes ou minutes, cela n'a aucun sens. Vous aurez besoin d'une sorte d'heuristique comme:

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

Si c'est généralement ce que vous voulez dire, vous voudrez probablement spécifier des poids pour chaque critère. – Servy

+0

Exactement. Vous aurez besoin de poids pour l'ajuster pour retourner la réponse que vous voulez. – IngisKahn

+1

@SteveWortham Les deux sont des possibilités légitimes, c'est pourquoi j'ai simplement demandé à l'OP plutôt que de supposer qu'il signifie l'un ou l'autre. – Servy

6

Peut-être que ce serait faire?

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

Vous devez modifier l'ordre des instructions pour indiquer lequel est le plus important.

+0

Vous pouvez utiliser 'FirstOrDefault' à la place pour éviter une éventuelle erreur 'InvalidOperationException' lorsque la séquence est vide. –

+0

Yup, édité pour l'inclure – Richard

0

Si je comprends bien votre question, je pense que la meilleure approche va être écrit des déclarations individuelles que vous mentionnez ...

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); 

Récupération divers Maxes et minutes à partir d'une seule requête Linq obtiendrait assez désordonné et je ne suis pas sûr qu'il y aurait un avantage avec l'efficacité, soit.

0

Tenir compte quelque chose comme ça ...

List<RestaurantRecord> _Restaurants; 

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

Cela étant dit, en utilisant un lambda dans ce cas aura des conséquences maintenabilité sur la route. Ce serait une bonne idée de refactoriser ceci, de sorte que si d'autres critères apparaissent à l'avenir (par exemple: accès au smartphone, type de cuisine?), Votre application peut être plus facilement modifiée pour s'adapter à ceux-ci.

Sur cette note, une mise en œuvre un peu mieux peut-être quelque chose comme:

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(); 
} 

J'espère que cela vous met sur la bonne voie. :)

1

Une alternative à avoir une heuristique pondérée est de classer par AverageRating, puis par ReviewCount, puis ...

Quelque chose comme cela devrait fonctionner:

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 
+0

Semblable à [l'approche de Richard] (http://stackoverflow.com/a/10986444/284240) à part cela vous préférez des restaurants plus loin;) –

+0

Peut-être que j'aime prendre de longs longs trajets? Bonne prise! –