Question

OK the title is ugly but the problem is quite straightforward:

I have a WPF control where I want to display plot lines. My "viewport" has its limits, and these limits (for example, bottom and top value in object coordinates) are doubles.

So I would like to draw lines at every multiple of, say, 5. If my viewport goes from -8.3 to 22.8, I would get [-5, 0, 5, 10, 15, 20].

I would like to use LINQ, it seems the natural candidate, but cannot find a way...

I imagine something along these lines:

int nlines = (int)((upper_value - lower_value)/step);
var seq = Enumerable.Range((int)(Math.Ceiling(magic_number)), nlines).Select(what_else);

Given values are (double)lower_value, (double)upper_value and (int)step.

Was it helpful?

Solution 2

Try this code:

double lower_value = -8.3;
double upper_value = 22.8;
int step = 5;

int low = (int)lower_value / step;
int up = (int)upper_value / step;

var tt = Enumerable.Range(low, up - low + 1).Select(i => i * step);

EDIT This code is intended for all negative values of the lower_value and for positive values which are divisible by the step. To make it work for all other positive values as well, the following correction should be applied:

if (lower_value > step * low)
    low++;

OTHER TIPS

Enumerable.Range should do the trick:

Enumerable.Range(lower_value, upper_value - lower_value)
          .Where(x => x % step == 0);

The first problem is to determine the nearest factor of your step value from your starting point. Some simple arithmetic can deduce this value:

public static double RoundToMultiple(double value, double multiple)
{
    return value - value % multiple;
}

To then create a sequence of all factors of a given value between a range an iterator block is well suited:

public static IEnumerable<double> FactorsInRange(
    double start, double end, double factor)
{
    var current  = RoundToMultiple(start, factor);
    while (start < end)
    {
        yield return start;
        current = current + factor;
    }
}

If you have the Generate method from MoreLinq, then you could write this without an explicit iterator block:

public static IEnumerable<double> FactorsInRange(
    double start, double end, double factor)
{
    return Generate(RoundToMultiple(start, factor),
        current => current + factor)
        .TakeWhile(current => current < end);
}

To avoid having to enumerate every number, you'll have to go outside of LINQ:

List<int> steps;
int currentStep = (lower_value / step) * step; //This takes advantage of integer division to "floor" the factor
steps.Add(currentStep);
while (currentStep < upper_value)
{
   currentStep += step;
   steps.Add(currentStep);
}

I made some adjustments to the code.

    private List<int> getMultiples(double lower_value, double upper_value, int step) {
        List<int> steps = new List<int>();
        int currentStep = (int)(lower_value / step) * step; //This takes advantage of integer division to "floor" the factor
        steps.Add(currentStep);
        while (currentStep <= upper_value) {
            steps.Add(currentStep);
            currentStep += step;
        }
        return steps;
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top