你怎么做呢?给定一个字节数组:
byte[] foo = new byte[4096];
如何将数组的前x个字节作为单独的数组?(具体来说,我需要它作为一个IEnumerable
)
这是为了与Socket
s合作.我认为最简单的方法是数组切片,类似于Perls语法:
@bar = @foo[0..40];
这会将前41个元素返回到@bar
数组中.C#中有些东西我只是缺少,还是还有其他一些我应该做的事情?
LINQ对我来说是一个选项(.NET 3.5),如果这有帮助的话.
你可以用ArraySegment
.它的重量非常轻,因为它不会复制数组:
string[] a = { "one", "two", "three", "four", "five" }; var segment = new ArraySegment( a, 1, 2 );
数组是可枚举的,所以你foo
已经是一个IEnumerable
本身.只需使用LINQ序列方法Take()
就可以得到你想要的东西(不要忘记包含Linq
命名空间 using System.Linq;
):
byte[] foo = new byte[4096]; var bar = foo.Take(41);
如果你真的需要任何IEnumerable
值的数组,你可以使用这个ToArray()
方法.这似乎不是这种情况.
您可以使用数组CopyTo()
方法.
或者使用LINQ,您可以使用Skip()
和Take()
...
byte[] arr = {1, 2, 3, 4, 5, 6, 7, 8}; var subset = arr.Skip(2).Take(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);
从C#8.0 / .Net Core 3.0开始
将支持数组切片,Index
并Range
添加新的类型。
范围结构文档
索引结构文档
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 }
上面的代码示例摘自C#8.0 博客。
请注意,^
前缀表示从数组末尾开始计数。如docs示例所示
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
并且Index
还可以在切片数组之外工作,例如使用循环
Range range = 1..4; foreach (var name in names[range])
将遍历条目1至4
请注意,在编写此答案时,C#8.0尚未正式发布
我在这里没有提到的另一种可能性:Buffer.BlockCopy()比Array.Copy()略快,它还具有能够从原始数组中即时转换的好处(比如说,简短) [])到一个字节数组,当你需要通过套接字传输数字数组时,它可以很方便.
在C#7.2中,您可以使用Span
.新System.Memory
系统的好处是它不需要复制数据.
你需要的方法是Slice
:
Spanslice = foo.Slice(0, 40);
很多方法现在支持Span
和IReadOnlySpan
,所以这将是非常简单的使用这个新的类型.
请注意,在编写本文时,Span
尚未在最新版本的.NET(4.7.1)中定义类型,因此要使用它,您需要从NuGet 安装System.Memory包.
这是一个简单的扩展方法,它将切片作为新数组返回:
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; }
然后你可以用它作为:
byte[] slice = foo.Slice(0, 40);
如果你想IEnumerable
,那就是
IEnumerabledata = foo.Take(x);
如果您不想添加LINQ或其他扩展,请执行以下操作:
float[] subArray = new List(myArray).GetRange(0, 8).ToArray();
您可以在原始数组(IList)周围使用包装器,就像在这个(未经测试的)代码段中一样.
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 <= 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 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 < this.endIndex; i++) { yield return this.source[i]; } } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion
}
byte[] foo = new byte[4096]; byte[] bar = foo.Take(40).ToArray();
对于字节数组,System.Buffer.BlockCopy将为您提供最佳性能。
您可以使用Take扩展方法
var array = new byte[] {1, 2, 3, 4}; var firstTwoItems = array.Take(2);