使用LINQ获取两个值之间整数的倍数序列



好吧,标题很难看,但问题很简单:

我有一个WPF控件,我想在其中显示打印线。我的"视口"有其限制,这些限制(例如,对象坐标中的底部和顶部值)是doubles

所以我想在每5的倍数上画一条线。如果我的视口从-8.3变为22.8,我会得到[-5, 0, 5, 10, 15, 20]

我想使用LINQ,它似乎是自然的候选者,但找不到方法。。。

我想象着这样的东西:

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

给定的值是(double)lower_value(double)upper_value(int)step

Enumerable.Range应该做到这一点:

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

试试这个代码:

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);

编辑此代码适用于lower_value的所有负值和可被step整除的正值。为了使其也适用于所有其他正值,应应用以下校正:

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

第一个问题是从起点确定步长值的最接近因子。一些简单的算术可以推导出这个值:

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

然后,为了在一个范围之间创建一个给定值的所有因子的序列,迭代器块非常适合:

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;
    }
}

如果你有来自MoreLinq的Generate方法,那么你可以在没有显式迭代器块的情况下写这个:

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

为了避免枚举每个数字,您必须退出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);
}

我对代码进行了一些调整。

    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;
    }

最新更新