C# Array of Increments
Asked Answered
B

8

8

If I want to generate an array that goes from 1 to 6 and increments by .01, what is the most efficient way to do this?

What I want is an array, with mins and maxs subject to change later...like this: x[1,1.01,1.02,1.03...]

Bernstein answered 23/5, 2012 at 13:43 Comment(4)
What about to use a loop with decimal value?Embellish
Define efficient... least code? Or fastest?Verde
increment by .01 the values inside the array? or increment the size of the array by 1?Pontus
If you mean fastest then hard-code it (assuming min/max/increment don't change).Isfahan
I
17

Assuming a start, end and an increment value, you can abstract this further:

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

Let's break it down:

Enumerable.Repeat takes a starting number, repeats for a given number of elements, and returns an enumerable (a collection). In this case, we start with the start element, find the difference between start and end and divide it by the increment (this gives us the number of increments between start and end) and add one to include the original number. This should give us the number of elements to use. Just be warned that since the increment is a decimal/double, there might be rounding errors when you cast to an int.

Select transforms all elements of an enumerable given a specific selector function. In this case, we're taking the number that was generated and the index, and adding the original number with the index multiplied by the increment.

Finally, the call to ToList will save the collection into memory.

If you find yourself using this often, then you can create a method to do this for you:

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()
}

Edit: Changed to using Repeat, so that non-whole number values will still be maintained. Also, there's no error checking being done here, so you should make sure to check that increment is not 0 and that start < end * sign(increment). The reason for multiplying end by the sign of increment is that if you're incrementing by a negative number, end should be before start.

Imogeneimojean answered 23/5, 2012 at 13:51 Comment(1)
+1 for actually showing where the numbers come from (and for using decimal).Isfahan
T
12

The easiest way is to use Enumerable.Range:

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

(hence efficient in terms of readability and lines of code)

Thermodynamic answered 23/5, 2012 at 13:50 Comment(6)
Good answer. One correction: the range you want is Enumerable.Range(100, 600).Birdsall
You should probably base all of the numbers off of the start, end, and increment, rather than calculating them all before hand and sticking magic numbers into the code.Atkinson
@jdmcnair: Corrected, although your Range(100, 600) would be a range from 1 to 7. Note that above excludes 6.00, if you need it take 501.Thermodynamic
doubles are evil for things like this, even when rounded. It's fixed decimal precicion, use a decimalCubic
What happens if the user wants to start with a non-integral number? IE: 0.01 to 0.5 using 0.002 increments?Imogeneimojean
if you divide by 100 rather than multiplying by 0.01, you don't need to call Math.Round().Yuki
S
5

I would just make a simple function.

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

Then you can turn that into an array, query it, or do whatever you want with it.

        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();
Simmonds answered 23/5, 2012 at 14:7 Comment(1)
I like this solution the best, as it is simply and has very little overhead compared to using LINQ (don't have to enumerate the collection twice, first to build the Enumerable with Range/Repeat, second for the Select function).Imogeneimojean
B
2

Use a for loop with 0.01 increments:

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

for (decimal i = 1; i <= 6; i+=0.01)
{
  myList.Add(i);
}
Battat answered 23/5, 2012 at 13:50 Comment(0)
H
1

Elegant

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

Efficient

Use for loop
Homozygote answered 23/5, 2012 at 13:51 Comment(0)
C
0

Whatever you do, don't use a floating point datatype (like double), they don't work for things like this on behalf of rounding behaviour. Go for either a decimal, or integers with a factor. For the latter:

Decimal[] decs = new Decimal[500];
for (int i = 0; i < 500; i++){
  decs[i] = (new Decimal(i) / 100)+1 ;
}
Cubic answered 23/5, 2012 at 13:48 Comment(2)
don't agree with "whatever you do, don't use floating point datatype" #619035Pontus
I was going for the more traditional 'binary floating point' definition of floating point ;)Cubic
D
0

You could solve it like this. The solution method returns a double array

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;
}
Dystopia answered 28/6, 2016 at 9:53 Comment(0)
S
-1
var ia = new float[500]; //guesstimate
var x = 0;
for(float i =1; i <6.01; i+= 0.01){
    ia[x] = i;
    x++;
}

You could multi-thread this for speed, but it's probably not worth the overhead unless you plan on running this on a really really slow processor.

Saw answered 23/5, 2012 at 13:50 Comment(3)
But I can't access ia outside the loop, can I? Isn't this a scope issue?Bernstein
I don't understand what you mean, ia was not defined inside the loop therefore it's is scope is not limited to inside the loopSaw
First: that doesn't fit in that array. Second, the implicit narrowing conversion doesn't work, you need i += 0.01F for this, third, you'll start getting rounding errors at 1.52Cubic

© 2022 - 2024 — McMap. All rights reserved.