Mr. Boy
Mr. Boy

Reputation: 63728

What's a good, neat way to create a new array from a portion of an existing array?

Given byte[] buffer I'd like to create a new array from a sub-array. A method signature might look like byte[] SubArray(byte[] buffer, int start, int length) but I'd probably rather just have a neat 1-liner than a method.

Here's a nice neat LINQ version but it feels like this mightn't be very efficient. Is there a standard library method that does this or would I have to create a new array then copy to it?

        var subArray = buffer.Skip(start).Take(length).ToArray();

Upvotes: 2

Views: 429

Answers (2)

user13094861
user13094861

Reputation:

  • ~3000 Milliseconds (for running 10000000 times and after trying several times):
subArray = buffer.Skip(2).Take(3).ToArray();
  • ~2600 Milliseconds:
subArray = buffer.ToList().GetRange(2, 3).ToArray();
  • ~2300 Milliseconds:
subArray = Enumerable.Range(2, 3).Select(x => buffer[x]).ToArray();
  • ~800 Milliseconds:
subArray = buffer[2..5];

This is a new feature in c# 8. I couldn't find any specific name but you'll find it by googling something like "c# range feature" or "c# range operator" or "c# binary infix operator with two expressions" or "Range Syntax c#". See Docs.

  • ~650 Milliseconds:
subArray = new byte[3];
Array.ConstrainedCopy(buffer, 2, subArray, 0, 3);
  • ~650 Milliseconds:
subArray = new byte[3];
Array.Copy(buffer, 2, subArray, 0, 3);

Upvotes: 2

Marc Gravell
Marc Gravell

Reputation: 1062885

There is no efficient way that involves creating a new array, however, there are other ways you can look at a portion of an array:

  • Memory<byte> / ReadOnlyMemory<byte> - effectively this is a "span provider"
  • Span<byte> / ReadOnlySpan<byte> - abstract view over any kind of raw memory (including arrays, interior pointers, and unmanaged memory), but can only be held on the stack - if you need to store it, you need the "memory", not the "span")
  • ArraySegment<byte> - explicitly just describes a vector/offset/count

All of the above have constructors that take a byte[] and an offset/count pair.

None of these require allocating / copying.

If you really really want a byte[], then:

var newArray = new byte[length];
Buffer.BlockCopy(oldArray, start, newArray, 0, length);

Upvotes: 3

Related Questions