C# equivalent of rotating a list using python slice operation

后端 未结 6 1725
借酒劲吻你
借酒劲吻你 2020-12-14 06:52

In python, I can take a list my_list and rotate the contents:

>>> my_list = list(range(10))
>>> my_list
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>         


        
6条回答
  •  时光说笑
    2020-12-14 07:17

    To rotate array, do a.Slice(1, null).Concat(a.Slice(null, 1)).

    Here's my stab at it. a.Slice(step: -1) gives a reversed copy as a[::-1].

    /// 
    /// Slice an array as Python.
    /// 
    /// 
    /// 
    /// start index.
    /// end index.
    /// step
    /// 
    /// 
    /// http://docs.python.org/2/tutorial/introduction.html#strings
    ///      +---+---+---+---+---+
    ///      | H | e | l | p | A |
    ///      +---+---+---+---+---+
    ///      0   1   2   3   4   5
    /// -6  -5  -4  -3  -2  -1    
    /// 
    public static IEnumerable Slice(this T[] array,
        int? start = null, int? end = null, int step = 1)
    {
        array.NullArgumentCheck("array");
        // step
        if (step == 0)
        {
            // handle gracefully
            yield break;
        }
        // step > 0
        int _start = 0;
        int _end = array.Length;
        // step < 0
        if (step < 0)
        {
            _start = -1;
            _end = -array.Length - 1;
        }
        // inputs
        _start = start ?? _start;
        _end = end ?? _end;
        // get positive index for given index
        Func toPositiveIndex = (int index, int length) =>
        {
            return index >= 0 ? index : index + length;
        };
        // start
        if (_start < -array.Length || _start >= array.Length)
        {
            yield break;
        }
        _start = toPositiveIndex(_start, array.Length);
        // end
        if (_end < -array.Length - 1)
        {
            yield break;
        }
        if (_end > array.Length)
        {
            _end = array.Length;
        }
        _end = toPositiveIndex(_end, array.Length);
        // slice
        if (step > 0)
        {
            // start, end
            if (_start > _end)
            {
                yield break;
            }
            for (int i = _start; i < _end; i += step)
            {
                yield return array[i];
            }
        }
        else
        {
            // start, end
            if (_end > _start)
            {
                yield break;
            }
            for (int i = _start; i > _end; i += step)
            {
                yield return array[i];
            }
        }
    }
    

    nunit tests:

    [Test]
    // normal cases
    [TestCase(3, 5, 1, 3, 4)]
    [TestCase(0, 5, 1, 0, 4)]
    [TestCase(3, null, 1, 3, 9)]
    [TestCase(0, null, 1, 0, 9)]
    [TestCase(null, null, 1, 0, 9)]
    [TestCase(0, 10, 1, 0, 9)]
    [TestCase(0, int.MaxValue, 1, 0, 9)]
    [TestCase(-1, null, 1, 9, 9)]
    [TestCase(-2, null, 1, 8, 9)]
    [TestCase(0, -2, 1, 0, 7)]
    // corner cases
    [TestCase(0, 0, 1, null, null)]
    [TestCase(3, 5, 2, 3, 3)]
    [TestCase(3, 6, 2, 3, 5)]
    [TestCase(100, int.MaxValue, 1, null, null)]
    [TestCase(int.MaxValue, 1, 1, null, null)]
    [TestCase(-11, int.MaxValue, 1, null, null)]
    [TestCase(-6, -5, 1, 4, 4)]
    [TestCase(-5, -6, 1, null, null)]
    [TestCase(-5, -5, 1, null, null)]
    [TestCase(0, -10, 1, null, null)]
    [TestCase(0, -11, 1, null, null)]
    [TestCase(null, null, 100, 0, 0)]
    // -ve step
    [TestCase(null, null, -1, 9, 0)]
    [TestCase(-7, -5, -1, null, null)]
    [TestCase(-5, -7, -1, 5, 4)]
    [TestCase(-5, -7, -2, 5, 5)]
    [TestCase(-7, null, -1, 3, 0)]
    public void Slice01(int? s, int? e, int i, int? first, int? last)
    {
        var a = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        var slice = a.Slice(start: s, end: e, step: i).ToArray();
        Print(slice);
        if (first.HasValue)
        {
            Assert.AreEqual(first, slice.First());
        }
        if (last.HasValue)
        {
            Assert.AreEqual(last, slice.Last());
        }
    }
    

提交回复
热议问题