循环-计算的最后一个元素不同

时间:2019-03-20 07:12:16

标签: c# algorithm linq

大家好(不好称呼),

我有一个循环,每次通过时我都能得到四舍五入的差异。我想对其进行累加并将其添加到我的结果的最后一条记录中。

var cumulatedRoundDifference = 0m;
var resultSet = Enumerable.Range(0, periods)
    .Select(currentPeriod => {
        var value = this.CalculateValue(currentPeriod);    
        var valueRounded = this.CommercialRound(value);

        // Bad part :(
        cumulatedRoundDifference += value - valueRounded; 
        if (currentPeriod == periods - 1)
           valueRounded = this.CommercialRound(value + valueRounded);

    return valuesRounded;
}

目前,我认为代码还不太好。 对于这种事情是否有一种模式/算法,或者对于Linq来说,它是聪明的,而循环外没有变量?

许多问候

2 个答案:

答案 0 :(得分:0)

您似乎正在做两件事-将所有内容四舍五入,然后计算总舍入误差。

可以删除lambda之外的变量,但随后需要两个查询。

var baseQuery = Enumerable.Range(0, periods)
   .Select(x => new { Value = CalculateValue(x), ValueRounded = CommercialRound(x) });
var cumulateRoundDifference = baseQuery.Select(x => x.Value - x.ValueRounded).Sum();
// LINQ isn't really good at doing something different to the last element
var resultSet = baseQuery.Select(x => x.ValueRounded).Take(periods - 1).Concat(new[] { CommercialRound(CalculateValue(periods - 1) + CommericalRound(periods - 1)) });

答案 1 :(得分:0)

  

Linq是否有用于这种事情的模式/算法,或者在循环外没有变量的情况下,它是不是很聪明?

我不太同意您要完成的工作。您正在尝试完成两个非常不同的任务,那么为什么要尝试将它们合并到同一迭代块中?后者(处理最后一项)甚至不应该是迭代。

出于可读性考虑,我建议将两者分开。这样做更有意义,不需要您检查是否在迭代的最后一个循环中(这可以节省一些代码和嵌套操作)。


虽然我不太了解计算本身,但是我可以回答您直接要求的算法(尽管我不确定这是最好的方法,我将在稍后解决在答案中。)

var allItemsExceptTheLastOne = allItems.Take(allItems.Count() - 1);

foreach(var item in allItemsExceptTheLastOne)
{
    // Your logic for all items except the last one
}

var theLastItem = allItems.Last();

// Your logic for the last item

我认为这是一种更清洁,更易读的方法。我不喜欢将lambda方法用作可读性不高的迷你方法。这可能是主观的,而且是个人风格的问题。


在重读时,我认为我对计算有更好的了解,因此我尝试实现它,同时尽我所能最大限度地提高可读性:

// First we make a list of the values (without the sum)

var myValues = Enumerable
                    .Range(0, periods)
                    .Select(period => this.CalculateValue(period))
                    .Select(period => period - this.CommercialRound(period))
                    .ToList();

// myValues = [ 0.1, 0.2, 0.3 ]

myValues.Add(myValues.Sum());

// myValues = [ 0.1, 0.2, 0.3, 0.6 ] 

这与我最初建议的算法相同:对可迭代项进行迭代,然后分别处理预期结果列表的最后一个值。

请注意,我将逻辑分为两个后续的Select语句,因为我认为这是最易读(没有过多的lambda体)和有效的方式(没有重复的CalculateValue调用)。但是,如果您更关注性能,例如当您希望处理大量列表时,可能需要再次合并它们。

我建议您始终尝试默认编写优于(过多)优化的可读性代码。并且仅在明显需要其他优化(我无法根据您的问题决定)的情况下才偏离该路径。


在第二次重读时,我不确定您是否已经对实际计算进行了足够的解释,因为cumulatedRoundDifference并未真正用于您的计算中,但是代码似乎表明其值对于最终结果。