重构 LINQ ...将列表中的属性和子属性相乘

发布于 2024-12-01 14:23:28 字数 1121 浏览 0 评论 0原文

我仍在接受 LINQ,并且尝试将以下 foreach 循环重构为它的 LINQ 等效项。这是我试图转换的 foreach 循环;

var NetTotal = 0M;

foreach (var cheque in ListOfCheques)
{
    var exchangeRate = (from exc in cheque.ExchangeRates
                        where exc.Type == EnumExchangeRate.ForCheque
                        select exc).FirstOrDefault();

    NetTotal = exchangeRate != null ? NetTotal + cheque.NetAmount * exchangeRate.Rate : NetTotal + cheque.NetAmount;
}

return NetTotal ;

以及我想出的 LINQ 代码;

var NetTotal = (from cheque in ListOfCheques
                join exc in ListOfCheques.SelectMany(b => b.ExchangeRates) on cheque.ID equals exrate.Cheque.ID into chequeWithRate
                where income.ExchangeRates.Select(x => x.Type).Equals(EnumExchangeRate.ForCheque)
                from ur in chequeWithRate.DefaultIfEmpty()
                select ur).Sum(x => x.Cheque.NetAmount * x.Rate);

return NetTotal;

我正在努力解决的重要问题;

  1. Check 类中的“ExchangeRates”列表可能不存在,即它不需要汇率。
  2. 如果没有找到汇率,它应该默认为 1。我该如何设置...我希望在 DefaultIfEmpty(1) 中设置它。

非常感谢任何帮助。

I am still coming to terms with LINQ and I am trying to refactor the following foreach loop into it's LINQ equivalent. Here's the foreach loop that I am trying to convert;

var NetTotal = 0M;

foreach (var cheque in ListOfCheques)
{
    var exchangeRate = (from exc in cheque.ExchangeRates
                        where exc.Type == EnumExchangeRate.ForCheque
                        select exc).FirstOrDefault();

    NetTotal = exchangeRate != null ? NetTotal + cheque.NetAmount * exchangeRate.Rate : NetTotal + cheque.NetAmount;
}

return NetTotal ;

and the LINQ code that I've come up with;

var NetTotal = (from cheque in ListOfCheques
                join exc in ListOfCheques.SelectMany(b => b.ExchangeRates) on cheque.ID equals exrate.Cheque.ID into chequeWithRate
                where income.ExchangeRates.Select(x => x.Type).Equals(EnumExchangeRate.ForCheque)
                from ur in chequeWithRate.DefaultIfEmpty()
                select ur).Sum(x => x.Cheque.NetAmount * x.Rate);

return NetTotal;

The important points that I am struggling with;

  1. It's possible that the "ExchangeRates" list within the Cheque class does not exist, i.e. it does not need an exchange rate.
  2. If there is no exchange rate found it should default to 1. How can I set that... I was hoping to set it within DefaultIfEmpty(1).

Any help is greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

调妓 2024-12-08 14:23:28

就像任何重构一样,只需一点一点地削减即可。首先,不要像这样使用 foreach 而是使用 Sum()

return ListOfCheques.Sum(c =>
{
    var exchangeRate = (from exc in c.ExchangeRates
        where exc.Type == EnumExchangeRate.ForCheque
        select exc).FirstOrDefault(); 
    return c.NetAmount * (exchangeRate ?? new ExchangeRate(){ Rate = 1 }).Rate;
});

(如果 ExchangeRate.Rate 属性的默认值为 1,那就太好了)

我会将 ExchangeRate 函数重写为简单的格式。您确定要 FirstOrDefault 而不是 SingleOrDefault 吗?

var exchangeRate = c.ExchangeRates.
    FirstOrDefault(ex => ex.Type == EnumExchangeRate.ForCheque);

然后可以将其交换到第一个语句中,将最终结果留在下面。

如果你愿意的话,就一个衬垫!

return ListOfCheques.Sum(c => c.NetAmount * 
    (c.ExchangeRates.FirstOrDefault(ex => ex.Type == EnumExchangeRate.ForCheque)
        ?? new ExchangeRate() { Rate = 1 }).Rate);

编辑

对 ?? 的澄清new ExchangeRate()

而不是执行 != null ? (amount * rates) : (rate) 我更喜欢将 ExchangeRate 对象与 Rate = 1 的新对象合并。我认为这提供了更流畅、更清晰的代码。我强烈建议您将默认汇率设置为 1.0,然后您可以简单地与 new ExchangeRate() 合并,而无需设置 Rate 属性。

要在新的 ExchangeRate 对象中设置 Rate 的默认值,只需将初始值设定项放入构造函数中

class ExchangeRate
{
    public ExchangeRate()
    {
        this.Rate = 1.0;
    }    
    // other stuff
}

Like any refactoring, just chip away piece by piece. Firstly, rather than foreach just use a Sum() like so.

return ListOfCheques.Sum(c =>
{
    var exchangeRate = (from exc in c.ExchangeRates
        where exc.Type == EnumExchangeRate.ForCheque
        select exc).FirstOrDefault(); 
    return c.NetAmount * (exchangeRate ?? new ExchangeRate(){ Rate = 1 }).Rate;
});

(it'd be nice if the default value for the ExchangeRate.Rate property was 1)

I'd rewrite the exchangeRate function to a simple format. Are you sure you want FirstOrDefault and not SingleOrDefault?

var exchangeRate = c.ExchangeRates.
    FirstOrDefault(ex => ex.Type == EnumExchangeRate.ForCheque);

and then this can be swapped into the first statement, leaving the resulting final product below.

A one liner if you want it to be!

return ListOfCheques.Sum(c => c.NetAmount * 
    (c.ExchangeRates.FirstOrDefault(ex => ex.Type == EnumExchangeRate.ForCheque)
        ?? new ExchangeRate() { Rate = 1 }).Rate);

edit

Clarification on the ?? new ExchangeRate()

Rather than doing the != null ? (amount * rate) : (rate) I prefer to coalesce the ExchangeRate object with a new such object with Rate = 1. I think this provides a smoother and cleaner piece of code. I'd strongly suggest you make the default Rate be 1.0, and then you can simply coalesce with a new ExchangeRate(), without needing to set the Rate property.

To set a default value for the Rate in a new ExchangeRate object, just put the initializer inside the constructor

class ExchangeRate
{
    public ExchangeRate()
    {
        this.Rate = 1.0;
    }    
    // other stuff
}
叹梦 2024-12-08 14:23:28

这个怎么样?

var query =
    from cheque in ListOfCheques
    let rate =
        cheque.ExchangeRates
            .Where(exc => exc.Type == EnumExchangeRate.ForCheque)
            .Select(exc => exc.Rate)
            .DefaultIfEmpty(1.0M)
            .First()
    select rate * cheque.NetAmount;

var NetTotal = query.Sum();

您的问题中给出的 LINQ 查询示例包含您没有解释的“额外”内容,因此我只包含 foreach 循环中的内容。

How about this?

var query =
    from cheque in ListOfCheques
    let rate =
        cheque.ExchangeRates
            .Where(exc => exc.Type == EnumExchangeRate.ForCheque)
            .Select(exc => exc.Rate)
            .DefaultIfEmpty(1.0M)
            .First()
    select rate * cheque.NetAmount;

var NetTotal = query.Sum();

Your LINQ query example given in your question has "extra" stuff that you didn't explain so I've only included the stuff from your foreach loop.

听风念你 2024-12-08 14:23:28

你需要这个吗?

           var query = from cheque in ListOfCheques
                        let excRates = cheque.ExchangeRates ?? Enumerable.Empty()
                        let rate = excRates.Where(x => x.Type == Something).Select(x => x.Rate).FirstOrDefault() ?? 1
                        select cheque.NetAmount * rate;

            var netTotal = query.Sum();

如果 Rate 可为空,您可以通过使其可为空来在 let 语句中适应它(例如 Select(x => new int?(x.Rate)) 或删除 ?? 1 并在您的 select 中适应它。这将使:

           var query = from cheque in ListOfCheques
                        let excRates = cheque.ExchangeRates ?? Enumerable.Empty()
                        let rate = excRates.Where(x => x.Type == Something).Select(x => x.Rate).FirstOrDefault()
                        select cheque.NetAmount * (rate != 0 ? rate : 1);

Do you need this?

           var query = from cheque in ListOfCheques
                        let excRates = cheque.ExchangeRates ?? Enumerable.Empty()
                        let rate = excRates.Where(x => x.Type == Something).Select(x => x.Rate).FirstOrDefault() ?? 1
                        select cheque.NetAmount * rate;

            var netTotal = query.Sum();

If Rate is nulllable, you can either adept that in the let statement by making it nullable (e.g. Select(x => new int?(x.Rate)) or remove ?? 1 and adept it in your select. which will make:

           var query = from cheque in ListOfCheques
                        let excRates = cheque.ExchangeRates ?? Enumerable.Empty()
                        let rate = excRates.Where(x => x.Type == Something).Select(x => x.Rate).FirstOrDefault()
                        select cheque.NetAmount * (rate != 0 ? rate : 1);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文