【问题标题】:Get the last N elements of an array in C#? [duplicate]在C#中获取数组的最后N个元素? [复制]
【发布时间】:2015-12-05 15:40:54
【问题描述】:

在 C# 中,返回数组最后 N 个元素的最有效方法是什么?

我正在处理包含数十万个元素的数组,我希望得到比基于 LINQ 的解决方案更有效的答案。

我还希望答案是经过单元测试的,以避免出现双重错误。

【问题讨论】:

  • 您尝试过什么来解决这个问题,您尝试过的解决方案遇到了什么问题?
  • 这是一个“分享你的知识,问答式”的条目。
  • 这绝不会降低问题或答案的质量标准。无论您是否发布答案,该问题都应该是一个质量问题,并且即使您是提出问题的人,答案也必须符合网站的标准。
  • 停止将元信息编辑到问题中。问题是您在哪里提出问题,而不是在哪里解释您提出问题的原因。
  • 这些答案使用 LINQ 和 IEnumerable,不使用数组。原始问题专门要求基于 LINQ 的解决方案,它不允许任何基于数组的解决方案。

标签: c# .net


【解决方案1】:

如下。单元测试适用于NUnit

[TestFixture]
public static class MyTakeLastExtensions
{   
    /// <summary>
    /// Intent: Returns the last N elements from an array.
    /// </summary>
    public static T[] MyTakeLast<T>(this T[] source, int n)
    {
        if (source == null)
        {
            throw new Exception("Source cannot be null.");
        }
        if (n < 0)
        {
            throw new Exception("Index must be positive.");
        }
        if (source.Length < n)
        {
            return source;
        }
        var result = new T[n];
        int c = 0;
        for (int i = source.Length - n; i < source.Length; i++)
        {
            result[c] = source[i];
            c++;
        }
        return result;
    }

    [Test]
    public static void MyTakeLast_Test()
    {
        int[] a = new[] {0, 1, 2};
        {
            var b = a.MyTakeLast(2);
            Assert.True(b.Length == 2);
            Assert.True(b[0] == 1);
            Assert.True(b[1] == 2);
        }

        {
            var b = a.MyTakeLast(3);
            Assert.True(b.Length == 3);
            Assert.True(b[0] == 0);
            Assert.True(b[1] == 1);
            Assert.True(b[2] == 2);
        }

        {
            var b = a.MyTakeLast(4);
            Assert.True(b.Length == 3);
            Assert.True(b[0] == 0);
            Assert.True(b[1] == 1);
            Assert.True(b[2] == 2);
        }

        {
            var b = a.MyTakeLast(1);
            Assert.True(b.Length == 1);
            Assert.True(b[0] == 2);
        }

        {
            var b = a.MyTakeLast(0);
            Assert.True(b.Length == 0);
        }

        {               
            Assert.Throws<Exception>(() => a.MyTakeLast(-1));
        }

        {
            int[] b = null;
            Assert.Throws<Exception>(() => b.MyTakeLast(-1));
        }
    }
}

【讨论】:

  • 如果你真的想在source.Length &lt; n的情况下返回源,为什么不在source.Length &lt;= n的时候呢?
  • 但是恕我直言,有时返回原始数组有时返回新数组是个坏主意。
  • 正如@Henrik 指出的那样,有时您只复制集合很奇怪 - 这会在更改原始集合时导致随机行为。如果您只使用原始集合就可以了,为什么还要制作副本 - 基本的yield return(或自定义迭代器)会更节省内存。
【解决方案2】:

我可能会写:

public static T[] TakeLast<T>(this T[] source, int n)
{
        if(source == null)
            throw new ArgumentNullException(nameof(source));
        if(n > source.Length)
            throw new ArgumentOutOfRangeException(nameof(n), "Can't be bigger than the array");
        if(n < 0)
            throw new ArgumentOutOfRangeException(nameof(n), "Can't be negative");

        var target = new T[n]; 
        Array.Copy(source, source.Length - n, target, 0, n);
        return target;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-21
    • 1970-01-01
    • 2017-08-31
    • 1970-01-01
    • 2011-02-16
    • 2022-09-29
    • 1970-01-01
    相关资源
    最近更新 更多