Suresh
Suresh

Reputation: 219

Generate sequence with step value

I have following inputs:

double zmin;
double zmax;
int count;
int N; //Total number of element in result array

I want to generate a sequence of double array with zmin as first and zmax as last value. But from second value until last but one it should be steзped by (zmax-zmin)/count.

Example:

zmin = 1;
zmax = 10;
count = 3

Expected result:

double[] result = { 1, 4, 7, 10}

My try:

double[] result = Enumerable.Repeat(zmin, N).Select(iv => (iv +(zmax-zmin)/count)).ToArray();

Upvotes: 9

Views: 7130

Answers (4)

William
William

Reputation: 2191

A bit cleaner than existing answers (as of 2020-01-22):

static IEnumerable<double> GetSteppedSequence(double from, double to, int numberOfSteps)
{
    if (numberOfSteps < 1)
    {
        throw new ArgumentOutOfRangeException(nameof(numberOfSteps), "Number of steps must be greater than zero.");
    }

    var stepSize = (to - from) / numberOfSteps;
    return Enumerable.Range(0, numberOfSteps + 1).Select(stepIndex => from + stepIndex * stepSize);
}

This uses multiplication instead of repeated addition, so that rounding errors are avoided.

Upvotes: 1

Wi8shadow
Wi8shadow

Reputation: 47

This is an improvement on existing answer from Muhammad Hasan Khan. The solution works fine but as the decimal error accumulates over time , it produces lot of error in decimal places over time.

First improvement on the existing solution is to get away with the accumulation of error like,

public static IEnumerable<double> Range(double min, double max, double step)
{
    double result = min;
    for (int i = 0; result<max; i++)
    {
        result = min + (step * i);
        yield return result;
    }
}

This solves the problem almost but if you are even pedantic to get rid of the dirt sometimes sticking around the decimal place, you can go a step further like,

public static IEnumerable<double> Range(double min, double max, double step)
{
    double result = min;
    int decPlaces = BitConverter.GetBytes(decimal.GetBits((decimal)step)[3])[2];
    for (int i = 0; result<max; i++)
    {
        result = min + (step * i);
        yield return Math.Round(result,decPlaces);
    }
}

And for the way how to call the above methods, just as an example,

double[] Myarray = classname.Range(0, 50, 0.01).ToArray();

will get you a double array with the mentioned parameters.

Upvotes: 3

Kamarey
Kamarey

Reputation: 11079

This one is good not only for numbers, but for more complex types as date/time.

The second method allows to provide result selector - useful in some cases.

public static IEnumerable<TItem> Range<TItem>(
    TItem itemFrom, TItem itemTo, Func<TItem, TItem> itemSelector
) where TItem : IComparable
{
    // Call to the below method
    return Range(itemFrom, itemTo, itemSelector, o => o);
}

public static IEnumerable<TItem> Range<TItem, TResult>(
    TItem itemFrom, TItem itemTo, Func<TItem, TItem> itemSelector, Func<TItem, TResult> resultSelector
) where TItem : IComparable
{
    while (true)
    {
        yield return resultSelector(itemFrom);

        if ((itemFrom = itemSelector(itemFrom)).CompareTo(itemTo) > 0)
            break;
    }
}

Usage:

Range(1, 10, o => o + 3);
1 
4 
7 
10
Range(
   DateTime.Now, 
   DateTime.Now.AddYears(1), 
   o => o.AddMonths(1), 
   o => o.ToString("MMMM"));
January 
February 
March 
April 
May 
June 
July 
August 
September 
October 
November 
December 
January

Upvotes: 1

Muhammad Hasan Khan
Muhammad Hasan Khan

Reputation: 35126

public static IEnumerable<double> Range(double min, double max, double step)
{
    double i;
    for (i=min; i<=max; i+=step)
        yield return i;

    if (i != max+step) // added only because you want max to be returned as last item
        yield return max; 
}

Upvotes: 11

Related Questions