【问题标题】:C# Array of IncrementsC# 增量数组
【发布时间】:2012-05-30 01:52:48
【问题描述】:

如果我想生成一个从 1 到 6 并以 0.01 递增的数组,那么最有效的方法是什么?

我想要的是一个数组,其最小值和最大值可能会在以后更改...就像这样:x[1,1.01,1.02,1.03...]

【问题讨论】:

  • 用十进制值循环怎么样?
  • 定义高效...最少的代码?还是最快?
  • 将数组中的值增加 0.01?还是将数组的大小增加 1?
  • 如果你的意思是最快的然后硬编码(假设 min/max/increment 不变)。

标签: c# arrays optimization loops increment


【解决方案1】:

无论您做什么,都不要使用浮点数据类型(如double),它们不适用于代表舍入行为的此类事情。选择decimal 或带因子的整数。对于后者:

Decimal[] decs = new Decimal[500];
for (int i = 0; i < 500; i++){
  decs[i] = (new Decimal(i) / 100)+1 ;
}

【讨论】:

【解决方案2】:

最简单的方法是使用Enumerable.Range

double[] result = Enumerable.Range(100, 500)
                  .Select(i => (double)i/100)
                  .ToArray();

(因此在可读性和代码行数方面很有效)

【讨论】:

  • 好答案。一个更正:您想要的范围是 Enumerable.Range(100, 600)。
  • 您可能应该将所有数字都基于开始、结束和增量,而不是事先计算所有数字并将魔术数字粘贴到代码中。
  • @jdmcnair:已更正,尽管您的 Range(100, 600) 的范围是 1 到 7。请注意,以上不包括 6.00,如果您需要,请使用 501。
  • 如果用户想以非整数开头怎么办? IE:0.01 到 0.5 使用 0.002 增量?
  • 如果除以 100 而不是乘以 0.01,则无需调用 Math.Round()。
【解决方案3】:
var ia = new float[500]; //guesstimate
var x = 0;
for(float i =1; i <6.01; i+= 0.01){
    ia[x] = i;
    x++;
}

你可以多线程来提高速度,但除非你打算在一个非常慢的处理器上运行它,否则它可能不值得开销。

【讨论】:

  • 但是我不能在循环外访问ia,可以吗?这不是范围问题吗?
  • 我不明白你的意思,ia 没有在循环内定义,因此它的范围不限于循环内
  • 第一:不适合该数组。其次,隐式缩小转换不起作用,为此您需要 i += 0.01F,第三,您将在 1.52 处开始出现舍入误差
【解决方案4】:

使用增量为 0.01 的 for 循环:

List<decimal> myList = new List<decimal>();

for (decimal i = 1; i <= 6; i+=0.01)
{
  myList.Add(i);
}

【讨论】:

    【解决方案5】:

    假设 startendincrement 值,您可以进一步抽象:

    Enumerable
        .Repeat(start, (int)((end - start) / increment) + 1)
        .Select((tr, ti) => tr + (increment * ti))
        .ToList()
    

    让我们分解一下:

    Enumerable.Repeat 接受一个起始数字,重复给定数量的元素,并返回一个可枚举(集合)。在这种情况下,我们从start 元素开始,找出startend 之间的差异,然后将其除以increment(这给出了startend 之间的增量数)和加一以包括原始数字。这应该给我们要使用的元素数量。请注意,由于 increment 是十进制/双精度,因此在转换为 int 时可能会出现舍入错误。

    Select 在给定特定选择器函数的情况下转换可枚举的所有元素。在这种情况下,我们将生成的数字和索引相加,然后将原始数字与索引乘以增量相加。

    最后,调用ToList 会将集合保存到内存中。

    如果您发现自己经常使用它,那么您可以创建一个方法来为您执行此操作:

    public static List<decimal> RangeIncrement(decimal start, decimal end, decimal increment)
    {
        return Enumerable
            .Repeat(start, (int)((end - start) / increment) + 1)
            .Select((tr, ti) => tr + (increment * ti))
            .ToList()
    }
    

    编辑:更改为使用重复,以便仍保留非整数值。此外,这里没有进行错误检查,因此您应该确保检查increment 不为0 并且start end * sign(increment)。将 end 乘以增量符号的原因是,如果您以负数递增,end 应该在 start 之前。

    【讨论】:

    • +1 用于实际显示数字的来源(以及使用decimal)。
    【解决方案6】:

    优雅

    double[] v = Enumerable.Range(1, 600).Select(x => x * 0.01).ToArray();
    

    高效

    Use for loop
    

    【讨论】:

      【解决方案7】:

      我只会做一个简单的函数。

          public IEnumerable<decimal> GetValues(decimal start, decimal end, decimal increment)
          {
              for (decimal i = start; i <= end; i += increment)
                  yield return i;
          }
      

      然后你可以把它变成一个数组,查询它,或者用它做任何你想做的事情。

              decimal[] result1 = GetValues(1.0m, 6.0m, .01m).ToArray();
              List<decimal> result2 = GetValues(1.0m, 6.0m, .01m).ToList();
              List<decimal> result3 = GetValues(1.0m, 6.0m, .01m).Where(d => d > 3 && d < 4).ToList();
      

      【讨论】:

      • 我最喜欢这个解决方案,因为与使用 LINQ 相比,它简单且开销很小(不必枚举集合两次,首先使用 Range/Repeat 构建 Enumerable,其次用于选择功能)。
      【解决方案8】:

      你可以这样解决。求解方法返回一个双精度数组

      double[] Solution(double min, int length, double increment)
      {
          double[] arr = new double[length];
          double value = min;
          arr[0] = value;
          for (int i = 1; i<length; i++)
          {
              value += increment;
              arr[i] = value;
          }
          return arr;
      }
      

      【讨论】:

        猜你喜欢
        • 2018-07-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-08
        • 2021-10-31
        相关资源
        最近更新 更多