10

I'd like to pass a sub-set of a C# array to into a method. I don't care if the method overwrites the data so would like to avoid creating a copy.

Is there a way to do this?

Thanks.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
user1400716
  • 1,126
  • 5
  • 13
  • 32

5 Answers5

19

Change the method to take an IEnumerable<T> or ArraySegment<T>.

You can then pass new ArraySegment<T>(array, 5, 2)

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • You may add an example of `IEnumerable` with `Skip` / `Take`. – Stefan Steinegger Jan 14 '13 at 18:15
  • 2
    @StefanSteinegger: `ArraySegment` implements `IEnumerable` – SLaks Jan 14 '13 at 18:22
  • You do lose fast element access though when using ArraySegment, which implements IEnumerable, IList, both of which dont guarantee O(1) for accessing a random element, right? – Tom Aug 05 '14 at 16:02
  • @t: `ArraySegment` is O(1). http://referencesource.microsoft.com/#mscorlib/system/arraysegment.cs#164 – SLaks Aug 05 '14 at 16:50
7

With C# 7.2 we have Span<T> . You can use the extension method AsSpan<T> for your array and pass it to the method without copying the sliced part. eg:

Method( array.AsSpan().Slice(1,3) )
uygar donduran
  • 1,177
  • 1
  • 9
  • 20
4

You can use the following class. Note you may need to modify it depending on whether you want endIndex to be inclusive or exclusive. You could also modify it to take a start and a count, rather than a start and an end index.

I intentionally didn't add mutable methods. If you specifically want them, that's easy enough to add. You may also want to implement IList if you add the mutable methods.

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();
    }
}
Servy
  • 202,030
  • 26
  • 332
  • 449
3

Arrays are immutable by size (i.e. you can't change size of a array), so you can only pass a subtracted copy of the original array. As option you can pass two indexes aside original array into method and operate on the basis of additional two indexes..

Ilya Ivanov
  • 23,148
  • 4
  • 64
  • 90
-4

you can use Linq take funktion and take as many elements from array as you want

var yournewarray = youroldarray.Take(4).ToArray();
COLD TOLD
  • 13,513
  • 3
  • 35
  • 52
  • 3
    If you add `ToArray` to the end then you're performing a copy. You'd also need to use both `Skip` and `Take` to get an arbitrary subset. Finally, if he wants quick indexed access within the subset he wouldn't get it from an `IEnumerable`. – Servy Jan 14 '13 at 18:12
  • -1: OP specifically posted he does _not_ want a copy. – Tom Aug 05 '14 at 15:53