【问题标题】:C# Array slice without copy没有副本的 C# 数组切片
【发布时间】:2013-01-14 18:01:55
【问题描述】:

我想将一个 C# 数组的子集传递给一个方法。我不在乎该方法是否会覆盖数据,因此希望避免创建副本。

有没有办法做到这一点?

谢谢。

【问题讨论】:

标签: c# arrays performance slice space-efficiency


【解决方案1】:

更改方法以获取IEnumerable<T>ArraySegment<T>

然后你可以通过new ArraySegment<T>(array, 5, 2)

【讨论】:

  • 您可以添加IEnumerable<T>Skip / Take 的示例。
  • @StefanSteinegger: ArraySegment<T> 实现 IEnumerable<T>
  • 在使用 ArraySegment 时,您确实会丢失快速元素访问,它实现了 IEnumerable、IList,这两者都不能保证 O(1) 访问随机元素,对吧?
  • @t: ArraySegment<T> 是 O(1)。 referencesource.microsoft.com/#mscorlib/system/…
【解决方案2】:

在 C# 7.2 中,我们有 Span<T> 。您可以为您的数组使用扩展方法AsSpan<T> 并将其传递给该方法,而无需复制切片部分。例如:

Method( array.AsSpan().Slice(1,3) )

【讨论】:

    【解决方案3】:

    您可以使用以下类。请注意,您可能需要修改它,具体取决于您希望 endIndex 具有包容性还是独占性。您还可以修改它以获取开始和计数,而不是开始和结束索引。

    我故意没有添加可变方法。如果您特别想要它们,那么添加起来很容易。如果添加可变方法,您可能还想实现IList

    public class Subset<T> : IReadOnlyList<T>
    {
        private IList<T> source;
        private int startIndex;
        private int endIndex;
        public Subset(IList<T> source, int startIndex, int endIndex)
        {
            this.source = source;
            this.startIndex = startIndex;
            this.endIndex = endIndex;
        }
    
        public T this[int i]
        {
            get
            {
                if (startIndex + i >= endIndex)
                    throw new IndexOutOfRangeException();
                return source[startIndex + i];
            }
        }
    
        public int Count
        {
            get { return endIndex - startIndex; }
        }
    
        public IEnumerator<T> GetEnumerator()
        {
            return source.Skip(startIndex)
                .Take(endIndex - startIndex)
                .GetEnumerator();
        }
    
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
    

    【讨论】:

      【解决方案4】:

      数组在大小上是不可变的(即您不能更改数组的大小),因此您只能传递原始数组的减去副本。作为选项,您可以将原始数组之外的两个索引传递给方法并在附加两个索引的基础上进行操作..

      【讨论】:

        【解决方案5】:

        您可以使用 Linq take funktion 并从数组中获取任意数量的元素

        var yournewarray = youroldarray.Take(4).ToArray();
        

        【讨论】:

        • 如果您将ToArray 添加到末尾,那么您正在执行复制。您还需要同时使用SkipTake 来获取任意子集。最后,如果他想在子集中进行快速索引访问,他不会从IEnumerable 获得它。
        • -1:OP 专门发布了他确实想要副本。
        猜你喜欢
        • 2015-04-18
        • 2020-01-18
        • 1970-01-01
        • 2019-04-17
        • 2012-11-10
        • 2010-09-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多