How do you do it? Given a byte array:

byte[] foo = new byte[4096]; 

How would I get the first x bytes of the array as a separate array? (Specifically, I need it as an IEnumerable<byte>)

This is for working with Sockets. I figure the easiest way would be array slicing, similar to Perls syntax:

@bar = @foo[0..40]; 

Which would return the first 41 elements into the @bar array. Is there something in C# that I'm just missing, or is there some other thing I should be doing?

LINQ is an option for me (.NET 3.5), if that helps any.

3

19 Answers

You could use ArraySegment<T>. It's very light-weight as it doesn't copy the array:

string[] a = { "one", "two", "three", "four", "five" }; var segment = new ArraySegment<string>( a, 1, 2 ); 
14

Arrays are enumerable, so your foo already is an IEnumerable<byte> itself. Simply use LINQ sequence methods like Take() to get what you want out of it (don't forget to include the Linq namespace with using System.Linq;):

byte[] foo = new byte[4096]; var bar = foo.Take(41); 

If you really need an array from any IEnumerable<byte> value, you could use the ToArray() method for that. That does not seem to be the case here.

5

You could use the arrays CopyTo() method.

Or with LINQ you can use Skip() and Take()...

byte[] arr = {1, 2, 3, 4, 5, 6, 7, 8}; var subset = arr.Skip(2).Take(2); 
5

Starting from C# 8.0/.Net Core 3.0

Array slicing will be supported, along with the new types Index and Range being added.

Range Struct docs
Index Struct docs

Index i1 = 3; // number 3 from beginning Index i2 = ^4; // number 4 from end int[] a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; Console.WriteLine($"{a[i1]}, {a[i2]}"); // "3, 6" var slice = a[i1..i2]; // { 3, 4, 5 } 

Above code sample taken from the C# 8.0 blog.

note that the ^ prefix indicates counting from the end of the array. As shown in the docs example

var words = new string[] { // index from start index from end "The", // 0 ^9 "quick", // 1 ^8 "brown", // 2 ^7 "fox", // 3 ^6 "jumped", // 4 ^5 "over", // 5 ^4 "the", // 6 ^3 "lazy", // 7 ^2 "dog" // 8 ^1 }; // 9 (or words.Length) ^0 

Range and Index also work outside of slicing arrays, for example with loops

Range range = 1..4; foreach (var name in names[range]) 

Will loop through the entries 1 through 4


note that at the time of writing this answer, C# 8.0 is not yet officially released
C# 8.x and .Net Core 3.x are now available in Visual Studio 2019 and onwards

2
static byte[] SliceMe(byte[] source, int length) { byte[] destfoo = new byte[length]; Array.Copy(source, 0, destfoo, 0, length); return destfoo; } 

//

var myslice = SliceMe(sourcearray,41); 
1

In C# 7.2, you can use Span<T>. The benefit of the new System.Memory system is that it doesn't need copying around data.

The method you need is Slice:

Span<byte> slice = foo.Slice(0, 40); 

A lot of methods now support Span and IReadOnlySpan, so it will be very straightforward to use this new type.

Note that at the time of writing the Span<T> type is not defined in the the most recent version of .NET yet (4.7.1) so to use it you need to install the System.Memory package from NuGet.

0

Another possibility I haven't seen mentioned here: Buffer.BlockCopy() is slightly faster than Array.Copy(), and it has the added benefit of being able to convert on-the-fly from an array of primitives (say, short[]) to an array of bytes, which can be handy when you've got numeric arrays that you need to transmit over Sockets.

2

C# 8 now (since 2019) supports Ranges which allows you to achieve Slice much easier (similar to JS syntax):

var array = new int[] { 1, 2, 3, 4, 5 }; var slice1 = array[2..^3]; // array[new Range(2, new Index(3, fromEnd: true))] var slice2 = array[..^3]; // array[Range.EndAt(new Index(3, fromEnd: true))] var slice3 = array[2..]; // array[Range.StartAt(2)] var slice4 = array[..]; // array[Range.All] 

You can use ranges instead of the well known LINQ functions: Skip(), Take(), Count().

0

If you want IEnumerable<byte>, then just

IEnumerable<byte> data = foo.Take(x); 

Here's a simple extension method that returns a slice as a new array:

public static T[] Slice<T>(this T[] arr, uint indexFrom, uint indexTo) { if (indexFrom > indexTo) { throw new ArgumentOutOfRangeException("indexFrom is bigger than indexTo!"); } uint length = indexTo - indexFrom; T[] result = new T[length]; Array.Copy(arr, indexFrom, result, 0, length); return result; } 

Then you can use it as:

byte[] slice = foo.Slice(0, 40); 

If you don't want to add LINQ or other extensions just do:

float[] subArray = new List<float>(myArray).GetRange(0, 8).ToArray(); 
2
byte[] foo = new byte[4096]; byte[] bar = foo.Take(40).ToArray(); 

You could use a wrapper around the original array (which is IList), like in this (untested) piece of code.

public class SubList<T> : IList<T> { #region Fields private readonly int startIndex; private readonly int endIndex; private readonly int count; private readonly IList<T> source; #endregion public SubList(IList<T> source, int startIndex, int count) { this.source = source; this.startIndex = startIndex; this.count = count; this.endIndex = this.startIndex + this.count - 1; } #region IList<T> Members public int IndexOf(T item) { if (item != null) { for (int i = this.startIndex; i <= this.endIndex; i++) { if (item.Equals(this.source[i])) return i; } } else { for (int i = this.startIndex; i <= this.endIndex; i++) { if (this.source[i] == null) return i; } } return -1; } public void Insert(int index, T item) { throw new NotSupportedException(); } public void RemoveAt(int index) { throw new NotSupportedException(); } public T this[int index] { get { if (index >= 0 && index < this.count) return this.source[index + this.startIndex]; else throw new IndexOutOfRangeException("index"); } set { if (index >= 0 && index < this.count) this.source[index + this.startIndex] = value; else throw new IndexOutOfRangeException("index"); } } #endregion #region ICollection<T> Members public void Add(T item) { throw new NotSupportedException(); } public void Clear() { throw new NotSupportedException(); } public bool Contains(T item) { return this.IndexOf(item) >= 0; } public void CopyTo(T[] array, int arrayIndex) { for (int i=0; i<this.count; i++) { array[arrayIndex + i] = this.source[i + this.startIndex]; } } public int Count { get { return this.count; } } public bool IsReadOnly { get { return true; } } public bool Remove(T item) { throw new NotSupportedException(); } #endregion #region IEnumerable<T> Members public IEnumerator<T> GetEnumerator() { for (int i = this.startIndex; i < this.endIndex; i++) { yield return this.source[i]; } } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion } 
3

For byte arrays System.Buffer.BlockCopy will give you the very best performance.

1

You can use Take extension method

var array = new byte[] {1, 2, 3, 4}; var firstTwoItems = array.Take(2); 

This may be a solution that:

var result = foo.Slice(40, int.MaxValue); 

Then the result is an IEnumerable< IEnumerable< byte>> with a first IEnumerable< byte> contains the first 40 bytes of foo, and a second IEnumerable< byte> holds the rest.

I wrote a wrapper class, the whole iteration is lazy, hope it could help:

public static class CollectionSlicer { public static IEnumerable<IEnumerable<T>> Slice<T>(this IEnumerable<T> source, params int[] steps) { if (!steps.Any(step => step != 0)) { throw new InvalidOperationException("Can't slice a collection with step length 0."); } return new Slicer<T>(source.GetEnumerator(), steps).Slice(); } } public sealed class Slicer<T> { public Slicer(IEnumerator<T> iterator, int[] steps) { _iterator = iterator; _steps = steps; _index = 0; _currentStep = 0; _isHasNext = true; } public int Index { get { return _index; } } public IEnumerable<IEnumerable<T>> Slice() { var length = _steps.Length; var index = 1; var step = 0; for (var i = 0; _isHasNext; ++i) { if (i < length) { step = _steps[i]; _currentStep = step - 1; } while (_index < index && _isHasNext) { _isHasNext = MoveNext(); } if (_isHasNext) { yield return SliceInternal(); index += step; } } } private IEnumerable<T> SliceInternal() { if (_currentStep == -1) yield break; yield return _iterator.Current; for (var count = 0; count < _currentStep && _isHasNext; ++count) { _isHasNext = MoveNext(); if (_isHasNext) { yield return _iterator.Current; } } } private bool MoveNext() { ++_index; return _iterator.MoveNext(); } private readonly IEnumerator<T> _iterator; private readonly int[] _steps; private volatile bool _isHasNext; private volatile int _currentStep; private volatile int _index; } 
0

I do not think C# supports the Range semantics. You could write an extension method though, like:

public static IEnumerator<Byte> Range(this byte[] array, int start, int end); 

But like others have said if you do not need to set a start index then Take is all you need.

Here is an extension function that uses a generic and behaves like the PHP function array_slice. Negative offset and length are allowed.

public static class Extensions { public static T[] Slice<T>(this T[] arr, int offset, int length) { int start, end; // Determine start index, handling negative offset. if (offset < 0) start = arr.Length + offset; else start = offset; // Clamp start index to the bounds of the input array. if (start < 0) start = 0; else if (start > arr.Length) start = arr.Length; // Determine end index, handling negative length. if (length < 0) end = arr.Length + length; else end = start + length; // Clamp end index to the bounds of the input array. if (end < 0) end = 0; if (end > arr.Length) end = arr.Length; // Get the array slice. int len = end - start; T[] result = new T[len]; for (int i = 0; i < len; i++) { result[i] = arr[start + i]; } return result; } } 
1
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace data_seniens { class Program { static void Main(string[] args) { //new list float [] x=new float[]{11.25f,18.0f,20.0f,10.75f,9.50f, 11.25f, 18.0f, 20.0f, 10.75f, 9.50f }; //variable float eat_sleep_area=x[1]+x[3]; //print foreach (var VARIABLE in x) { if (VARIABLE < x[7]) { Console.WriteLine(VARIABLE); } } //keep app run Console.ReadLine(); } } } 
0