C# 增量数组

8
如果我想生成一个从1到6,每次增加0.01的数组,最有效的方法是什么?
我想要一个数组,mins和maxs稍后可能会更改...就像这样:x [1,1.01,1.02,1.03 ...]

使用带有小数值的循环怎么样? - Terminador
6
定义高效,是指编写尽可能少的代码还是最快的执行速度? - James Michael Hare
将数组内的值增加0.01?还是将数组的大小增加1? - gsharp
3
如果你想要最快的话,那就硬编码它(假设最小值/最大值/增量不变)。 - George Duckett
8个回答

16
假定有一个起始值start,结束值end和步长increment,你可以进一步抽象化这个概念:
Enumerable
    .Repeat(start, (int)((end - start) / increment) + 1)
    .Select((tr, ti) => tr + (increment * ti))
    .ToList()
让我们分解一下: Enumerable.Repeat 接收一个起始数字,重复给定数量的元素,并返回一个可枚举集合。在这种情况下,我们从 start 元素开始,找到 startend 之间的差异并除以 increment(这给我们了 start end 之间增量的数量),然后加上一来包括原始数字。这应该给我们要使用的元素数量。只需注意,由于 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()
}

编辑:改用 Repeat,以便非整数值仍将保留。此外,此处未执行错误检查,因此应确保检查 increment 不为 0,并且 start < end * sign(increment)。将 end 乘以增量符号的原因是,如果您正在按负数增加,则结束应该在开始之前。


3
感谢您明确给出数字来源并使用decimal库,我为此点赞。(原文已被成功翻译) - George Duckett

12
最简单的方法是使用Enumerable.Range函数:
double[] result = Enumerable.Range(100, 500)
                  .Select(i => (double)i/100)
                  .ToArray();

(因此在可读性和代码行数方面更加高效)


2
好的回答。一个更正:你想要的范围是 Enumerable.Range(100, 600)。 - jdmcnair
1
你应该基于起始值、结束值和增量来计算所有数字,而不是预先计算它们并将魔数插入代码中。 - Servy
@jdmcnair:已经更正,尽管您的 Range(100, 600) 是从1到7的范围。请注意,上面排除了 6.00,如果需要,请取501。 - Tim Schmelter
“doubles” 对于这种事情来说是有问题的,即使四舍五入也不行。应该使用固定小数精度的“decimal”。 - Martijn
1
如果用户想要以非整数开始,会发生什么?例如:使用0.002增量从0.01到0.5。 - SPFiredrake
1
如果你除以100而不是乘以0.01,就不需要调用Math.Round()。 - phoog

5
我只会创建一个简单的函数。
    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,第二次用Select函数)。 - SPFiredrake

2

使用for循环并以0.01为增量:

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

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

1

优雅

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

高效

Use for loop

0
你可以这样解决。解决方法返回一个双精度数组。
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;
}

0
无论你做什么,都不要使用浮点数据类型(如double),因为它们在处理舍入行为等方面不适用于此类事情。选择使用decimal或带有因子的整数。对于后者:
Decimal[] decs = new Decimal[500];
for (int i = 0; i < 500; i++){
  decs[i] = (new Decimal(i) / 100)+1 ;
}

不要赞同“无论如何,不要使用浮点数据类型”的说法。https://dev59.com/uXRB5IYBdhLWcg3wc280 - gsharp
我更倾向于传统的“二进制浮点数”定义,;) - Martijn

-1
var ia = new float[500]; //guesstimate
var x = 0;
for(float i =1; i <6.01; i+= 0.01){
    ia[x] = i;
    x++;
}

你可以使用多线程来提高速度,但除非你计划在一个非常慢的处理器上运行此程序,否则这可能不值得开销。


但是我不能在循环外访问ia,对吗?这不是作用域问题吗? - Kevin Brown
我不明白你的意思,ia没有在循环内定义,因此它的作用域不仅限于循环内部。 - Jaimal Chohan
首先:那个不适合在那个数组里。其次,隐式的缩小转换无法工作,你需要使用 i += 0.01F,第三,当数值达到1.52时你将开始获得舍入误差。 - Martijn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接