C# 相当于 Python 的范围与步骤?

bud*_*udi 5 c# python ienumerable range

是否有与Python 的rangestep等效的 C# ?


文档:

对于正数step,范围的内容r由公式r[i] = start + step*iwherei >= 0和确定r[i] < stop

对于负数step,范围的内容仍然由公式确定r[i] = start + step*i,但约束条件是i >= 0r[i] > stop


例子:

>>> list(range(0, 10, 3))
[0, 3, 6, 9]
>>> list(range(0, -10, -1))
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
Run Code Online (Sandbox Code Playgroud)

Ser*_*kiy 6

我会采用两种方法实现。第一个用于参数验证并提供默认值:

public static IEnumerable<int> Range(int start, int stop, int step = 1)
{
    if (step == 0)
        throw new ArgumentException(nameof(step));

    return RangeIterator(start, stop, step);
}
Run Code Online (Sandbox Code Playgroud)

这是具有延迟执行的迭代器所必需的。否则,在执行迭代器之前您不会验证参数。这可能会在您获得迭代器引用很长时间后发生。以及迭代器本身(实际上,在 C# 7 中,您可以使用本地函数而不是创建单独的方法):

private static IEnumerable<int> RangeIterator(int start, int stop, int step)
{
    int x = start;

    do
    {
        yield return x;
        x += step;
        if (step < 0 && x <= stop || 0 < step && stop <= x)
            break;
    }
    while (true);
}
Run Code Online (Sandbox Code Playgroud)

为了实现 Python 的 range 行为,我们还需要一种只接受stop参数的方法。我们可以使用 C# 6 表达式主体成员来简化代码:

public static IEnumerable<int> Range(int stop) => RangeIterator(0, stop, 1);
Run Code Online (Sandbox Code Playgroud)

您还可以使用C# 6在全局范围内使用静态方法。假设具有 Range 方法描述的类名为 PythonUtils:

using static YourNamespace.PythonUtils;
Run Code Online (Sandbox Code Playgroud)

代码中的用法如下

foreach(var i in Range(0, 10, 3))
   Print(i);
Run Code Online (Sandbox Code Playgroud)

您也可以使用默认值

Range(0, 10, 3)     // [0,3,6,9]
Range(4, -3, -1)    // [4,3,2,1,0,-1,-2]
Range(5)            // [0,1,2,3,4]
Range(2, 5)         // [2,3,4]
Run Code Online (Sandbox Code Playgroud)

看起来像 Pascal-case Python :)


bud*_*udi 4

我们可以实现一个static实用程序类来处理这个问题。

为了完整起见,此解决方案模仿 Pythonrange对于一个参数 ( stop)、两个参数 ( start, stop) 和三个参数 ( start, stop, step) 的行为:

using System;
using System.Collections.Generic;

public static class EnumerableUtilities
{
    public static IEnumerable<int> RangePython(int start, int stop, int step = 1)
    {
        if (step == 0)
            throw new ArgumentException("Parameter step cannot equal zero.");

        if (start < stop && step > 0)
        {
            for (var i = start; i < stop; i += step)
            {
                yield return i;
            }
        }
        else if (start > stop && step < 0)
        {
            for (var i = start; i > stop; i += step)
            {
                yield return i;
            }
        }
    }

    public static IEnumerable<int> RangePython(int stop)
    {
        return RangePython(0, stop);
    }
}
Run Code Online (Sandbox Code Playgroud)

步骤的用法示例:

foreach (var i in EnumerableUtilities.RangePython(0, 10, 3))
{
    Console.WriteLine(i);
}
Run Code Online (Sandbox Code Playgroud)

输出:

0
3
6
9
Run Code Online (Sandbox Code Playgroud)