可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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 Socket
s. 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.