Array slices in C#

匿名 (未验证) 提交于 2019-12-03 01:50:02

问题:

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)

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.

回答1:

Arrays are enumerable, so your foo already is an IEnumerable 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 value, you could use the ToArray() method for that. That does not seem to be the case here.



回答2:

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

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


回答3:

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); 


回答4:

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); 


回答5:

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.



回答6:

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

public static T[] Slice(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); 


回答7:

If you want IEnumerable, then just

IEnumerable data = foo.Take(x); 


回答8:

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

public class SubList : IList {     #region Fields  private readonly int startIndex; private readonly int endIndex; private readonly int count; private readonly IList source;  #endregion  public SubList(IList source, int startIndex, int count) {     this.source = source;     this.startIndex = startIndex;     this.count = count;     this.endIndex = this.startIndex + this.count - 1; }  #region IList Members  public int IndexOf(T item) {     if (item != null)     {         for (int i = this.startIndex; i = 0 && index = 0 && index  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 Members  public IEnumerator GetEnumerator() {     for (int i = this.startIndex; i 

}



回答9:

byte[] foo = new byte[4096];   byte[] bar = foo.Take(40).ToArray(); 


回答10:

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

float[] subArray = new List(myArray).GetRange(0, 8).ToArray(); 


回答11:

You can use Take extension method

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


回答12:

This may be a solution that:

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

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

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

public static class CollectionSlicer {     public static IEnumerable> Slice(this IEnumerable 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(source.GetEnumerator(), steps).Slice();     } }  public sealed class Slicer {     public Slicer(IEnumerator iterator, int[] steps)     {         _iterator = iterator;         _steps = steps;         _index = 0;         _currentStep = 0;         _isHasNext = true;     }      public int Index     {         get { return _index; }     }      public IEnumerable> Slice()     {         var length = _steps.Length;         var index = 1;         var step = 0;          for (var i = 0; _isHasNext; ++i)         {             if (i  SliceInternal()     {         if (_currentStep == -1) yield break;         yield return _iterator.Current;          for (var count = 0; count  _iterator;     private readonly int[] _steps;     private volatile bool _isHasNext;     private volatile int _currentStep;     private volatile int _index; } 


回答13:

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



回答14:

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(this T[] arr, int offset, int length)     {         int start, end;          // Determine start index, handling negative offset.         if (offset  arr.Length)             start = arr.Length;          // Determine end index, handling negative length.         if (length  arr.Length)             end = arr.Length;          // Get the array slice.         int len = end - start;         T[] result = new T[len];         for (int i = 0; i 


回答15:

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

public static IEnumerator 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.



文章来源: Array slices in C#
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!