不复制的 C# 数组切片

10
我希望将 C# 数组的子集传递给方法,但不关心方法是否会覆盖数据,因此想避免创建副本。有没有办法做到这一点?谢谢。

你可能会对ArraySlice<T>感兴趣:https://github.com/henon/SliceAndDice - henon
5个回答

19

将方法更改为接受 IEnumerable<T>ArraySegment<T>

然后可以传递 new ArraySegment<T>(array, 5, 2)


您可以添加一个IEnumerable<T>的示例,其中包含Skip / Take - Stefan Steinegger
2
@StefanSteinegger:ArraySegment<T> 实现了 IEnumerable<T> - SLaks
当使用实现IEnumerable和IList的ArraySegment时,您会失去快速元素访问,这两者都不能保证O(1)来访问随机元素,对吧? - Tom
@t: ArraySegment<T> 是 O(1)。http://referencesource.microsoft.com/#mscorlib/system/arraysegment.cs#164 - SLaks

7

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

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

4
您可以使用以下类。请注意,根据您是否希望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();
    }
}

3

数组大小不可变(即无法更改数组的大小),因此您只能传递原始数组的一个减去后的副本。作为选项,您可以将两个索引与原始数组一起传递到方法中,并基于这两个额外的索引进行操作。


-4

你可以使用 Linq 的 Take 函数,从数组中取出任意数量的元素。

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

3
如果在末尾添加 ToArray,则会执行一次拷贝。您还需要同时使用 SkipTake 来获取任意子集。最后,如果他想要在子集内进行快速索引访问,则无法从 IEnumerable 中获得。 - Servy
-1:OP明确表示他不想要复制。 - Tom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接