【问题标题】:Get a sequence of multiples of an integer between two values using LINQ使用 LINQ 获取两个值之间的整数倍数序列
【发布时间】:2014-04-16 20:29:11
【问题描述】:

好吧,标题很丑,但问题很简单:

我有一个 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

【问题讨论】:

    标签: c# linq sequence


    【解决方案1】:

    Enumerable.Range 应该可以解决问题:

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

    【讨论】:

    • 快点打败我吧!请注意,您需要先将较低/较高的值转换为整数(带有转换的 Math.Floor 会更好)
    • Range 第二个参数似乎是“计数”,而不是“上限值”,是吗?
    • 这仅适用于整数步长,对于大步长值来说效率极低。它也只对小于int.MaxValue 的范围有效,并且完全在int.MinValueint.MaxValue 的范围内,这比double 的范围更严格。
    【解决方案2】:

    试试这个代码:

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

    【讨论】:

    • 这是@paqogomez 答案的由内而外的版本,通过预先进行逐步缩小来避免生成后测试。会试一试,很快就会给你一些反馈。谢谢。
    • 这仍然会枚举范围内的每个数字。
    • @LordTakkera 否。Enumerable.Range 在结果中返回尽可能多的值。
    • @LordTakkera 不同之处在于范围已经更小了,因为lowup 的 pre-linq 划分为 step
    【解决方案3】:

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

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

    如果你有Generate method from MoreLinq,那么你可以在没有显式迭代器块的情况下编写它:

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

    【讨论】:

    • 这很漂亮,但你能想到(很抱歉甚至问)这种“单线”版本吗?
    • @heltonbiker 即使可以,我也不想这样做。我认为这是这个问题设计得最好的解决方案,它既正确又最容易理解、维护和改进。如果您从 MoreLinq 的 Generate 方法开始,那么额外的代码可能会缩小。
    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多