我在C#中有3个字节的数组,我需要组合成一个.什么是最有效的方法来完成这项任务?
对于原始类型(包括字节),请使用System.Buffer.BlockCopy
而不是System.Array.Copy
.它更快.
我使用3个10字节的数组,在一个循环中执行了100万次的每个建议方法.结果如下:
新的字节数组使用System.Array.Copy
- 0.2187556秒
新的字节数组使用System.Buffer.BlockCopy
- 0.1406286秒
IEnumerable
IEnumerable
我将每个数组的大小增加到100个元素并重新运行测试:
新的字节数组使用System.Array.Copy
- 0.2812554秒
新的字节数组使用System.Buffer.BlockCopy
- 0.2500048秒
IEnumerable
IEnumerable
我将每个数组的大小增加到1000个元素并重新运行测试:
新的字节数组使用System.Array.Copy
- 1.0781457秒
新的字节数组使用System.Buffer.BlockCopy
- 1.0156445秒
IEnumerable
IEnumerable
最后,我将每个数组的大小增加到100万个元素并重新运行测试,每个循环只执行4000次:
新的字节数组使用System.Array.Copy
- 13.4533833秒
新的字节数组使用System.Buffer.BlockCopy
- 13.1096267秒
IEnumerable
IEnumerable
因此,如果您需要一个新的字节数组,请使用
byte[] rv = new byte[a1.Length + a2.Length + a3.Length]; System.Buffer.BlockCopy(a1, 0, rv, 0, a1.Length); System.Buffer.BlockCopy(a2, 0, rv, a1.Length, a2.Length); System.Buffer.BlockCopy(a3, 0, rv, a1.Length + a2.Length, a3.Length);
但是,如果你可以使用IEnumerable
,那么DEFINITELY更喜欢LINQ的Concat <>方法.它只比C#yield运算符略慢,但更简洁,更优雅.
IEnumerablerv = a1.Concat(a2).Concat(a3);
如果你有任意数量的数组并使用.NET 3.5,你可以使System.Buffer.BlockCopy
解决方案更通用,如下所示:
private byte[] Combine(params byte[][] arrays) { byte[] rv = new byte[arrays.Sum(a => a.Length)]; int offset = 0; foreach (byte[] array in arrays) { System.Buffer.BlockCopy(array, 0, rv, offset, array.Length); offset += array.Length; } return rv; }
*注意:上面的块要求您在顶部添加以下命名空间才能工作.
using System.Linq;
对于Jon Skeet关于后续数据结构迭代(字节数组与IEnumerable
新的字节数组使用System.Array.Copy
- 78.20550510秒
新的字节数组使用System.Buffer.BlockCopy
- 77.89261900秒
IEnumerable
IEnumerable
关键是,理解结果数据结构的创建和使用的效率非常重要.仅仅关注创建的效率可能会忽略与使用相关的低效率.荣誉,乔恩.
在我看来,许多答案都忽略了规定的要求:
结果应该是一个字节数组
它应该尽可能高效
这两个一起排除了一个LINQ字节序列 - 任何东西yield
都会使得无法在不迭代整个序列的情况下获得最终大小.
如果那些当然不是真正的要求,LINQ可能是一个非常好的解决方案(或IList
实现).但是,我会假设Superdumbell知道他想要什么.
(编辑:我刚才有另外一个想法.制作数组副本和懒散地阅读它们之间存在很大的语义差异.考虑一下如果在调用Combine
(或者其他)之后更改其中一个"源"数组中的数据会发生什么)方法但在使用结果之前 - 使用延迟评估,该变化将是可见的.使用立即复制,它不会.不同的情况将要求不同的行为 - 只需注意一些事情.)
以下是我提出的方法 - 与其他一些答案中包含的方法非常相似,当然:)
public static byte[] Combine(byte[] first, byte[] second) { byte[] ret = new byte[first.Length + second.Length]; Buffer.BlockCopy(first, 0, ret, 0, first.Length); Buffer.BlockCopy(second, 0, ret, first.Length, second.Length); return ret; } public static byte[] Combine(byte[] first, byte[] second, byte[] third) { byte[] ret = new byte[first.Length + second.Length + third.Length]; Buffer.BlockCopy(first, 0, ret, 0, first.Length); Buffer.BlockCopy(second, 0, ret, first.Length, second.Length); Buffer.BlockCopy(third, 0, ret, first.Length + second.Length, third.Length); return ret; } public static byte[] Combine(params byte[][] arrays) { byte[] ret = new byte[arrays.Sum(x => x.Length)]; int offset = 0; foreach (byte[] data in arrays) { Buffer.BlockCopy(data, 0, ret, offset, data.Length); offset += data.Length; } return ret; }
当然,"params"版本需要首先创建一个字节数组的数组,这会带来额外的低效率.
为了代码清洁,我进一步采用了Matt的LINQ示例:
byte[] rv = a1.Concat(a2).Concat(a3).ToArray();
就我而言,阵列很小,所以我不关心性能.
如果您只需要一个新的字节数组,请使用以下命令:
byte[] Combine(byte[] a1, byte[] a2, byte[] a3) { byte[] ret = new byte[a1.Length + a2.Length + a3.Length]; Array.Copy(a1, 0, ret, 0, a1.Length); Array.Copy(a2, 0, ret, a1.Length, a2.Length); Array.Copy(a3, 0, ret, a1.Length + a2.Length, a3.Length); return ret; }
或者,如果您只需要一个IEnumerable,请考虑使用C#2.0 yield运算符:
IEnumerableCombine(byte[] a1, byte[] a2, byte[] a3) { foreach (byte b in a1) yield return b; foreach (byte b in a2) yield return b; foreach (byte b in a3) yield return b; }
我实际上遇到了使用Concat的一些问题...(在1000万的阵列中,它实际上已经崩溃了).
我发现以下内容简单,容易并且运行良好而不会崩溃,它适用于任意数量的数组(不仅仅是三个)(它使用LINQ):
public static byte[] ConcatByteArrays(params byte[][] arrays) { return arrays.SelectMany(x => x).ToArray(); }
memorystream类对我来说非常好.我无法让缓冲类以与memorystream一样快的速度运行.
using (MemoryStream ms = new MemoryStream()) { ms.Write(BitConverter.GetBytes(22),0,4); ms.Write(BitConverter.GetBytes(44),0,4); ms.ToArray(); }