How to “let” in lambda expression?

夙愿已清 提交于 2019-11-27 05:21:36

问题


How can I rewrite this linq query to Entity on with lambda expression?
I want to use let keyword or an equivalent in my lambda expression.

var results = from store in Stores
              let AveragePrice =  store.Sales.Average(s => s.Price)
              where AveragePrice < 500 && AveragePrice > 250

For some similar questions like what is commented under my question, it's suggested to

.Select(store=> new { AveragePrice = store.Sales.Average(s => s.Price), store})

which will calculate AveragePrice for each item, while in Query style I mentioned, let expression prevents to calculate average many times.


回答1:


So, you can use the extension method syntax, which would involve one lambda expression more than you are currently using. There is no let, you just use a multi-line lambda and declare a variable:

var results = Stores.Where(store => 
{
    var averagePrice = store.Sales.Average(s => s.Price);
    return averagePrice > 250 && averagePrice < 500;
});

Note that I changed the average price comparison, because yours would never return any results (more than 500 AND less that 250).

The alternative is

var results = Stores.Select(store => new { Store = store, AveragePrice = store.Sales.Average(s => s.Price})
    .Where(x => x.AveragePrice > 250 && x.AveragePrice < 500)
    .Select(x => x.Store);



回答2:


Basically, you need to use Select and an anonymous type to add the average to your object, followed by the rest of your statement.

Not tested but it should look like this:

Stores.Select(
x => new { averagePrice = x.Sales.Average(s => s.Price), store = x})
.Where(y => y.averagePrice > 500 && y.averagePrice < 250)
.Select(x => x.store);

Warning, be careful with these constructs. Using let creates a new anonymous type per object in your collection, it consumes a lot of memory with large collections ...

Look here for details: Let in chained extension methods




回答3:


Another option is to define this extension method:

public static class Functional
{
    public static TResult Pipe<T, TResult>(this T value, Func<T, TResult> func)
    {
        return func(value);
    }
}    

Then write your query like this:

var results = Stores
    .Where(store => store.Sales.Average(s => s.Price)
        .Pipe(averagePrice => averagePrice < 500 && averagePrice > 250));



回答4:


We can avoid the overhead of the lambda used in all the other answers with an inline out declaration:

public static class FunctionalExtensions
{
    public static T Assign<T>(this T o, out T result) =>
        result = o;
}

And call it like this

var results = Stores
    .Where(store => store.Sales
        .Average(s => s.Price)
        .Assign(out var averagePrice) < 500 && averagePrice > 250);


来源:https://stackoverflow.com/questions/9240375/how-to-let-in-lambda-expression

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!