我在c#中有3个字节数组,我需要合并成一个。完成这项任务最有效的方法是什么?
当前回答
/// <summary>
/// Combine two Arrays with offset and count
/// </summary>
/// <param name="src1"></param>
/// <param name="offset1"></param>
/// <param name="count1"></param>
/// <param name="src2"></param>
/// <param name="offset2"></param>
/// <param name="count2"></param>
/// <returns></returns>
public static T[] Combine<T>(this T[] src1, int offset1, int count1, T[] src2, int offset2, int count2)
=> Enumerable.Range(0, count1 + count2).Select(a => (a < count1) ? src1[offset1 + a] : src2[offset2 + a - count1]).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操作符:
IEnumerable<byte> Combine(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;
}
/// <summary>
/// Combine two Arrays with offset and count
/// </summary>
/// <param name="src1"></param>
/// <param name="offset1"></param>
/// <param name="count1"></param>
/// <param name="src2"></param>
/// <param name="offset2"></param>
/// <param name="count2"></param>
/// <returns></returns>
public static T[] Combine<T>(this T[] src1, int offset1, int count1, T[] src2, int offset2, int count2)
=> Enumerable.Range(0, count1 + count2).Select(a => (a < count1) ? src1[offset1 + a] : src2[offset2 + a - count1]).ToArray();
对于基元类型(包括字节),使用System.Buffer.BlockCopy而不是System.Array.Copy。这是更快。
我在循环中对每个建议的方法进行计时,每个方法使用3个10字节的数组执行了100万次。以下是调查结果:
使用System.Array.Copy创建字节数组- 0.2187556秒 使用System.Buffer.BlockCopy创建字节数组- 0.1406286秒 IEnumerable<字节>使用c# yield运算符- 0.0781270秒 IEnumerable<byte> using LINQ's Concat<> - 0.0781270秒
我将每个数组的大小增加到100个元素,并重新运行测试:
使用System.Array.Copy创建字节数组- 0.2812554秒 使用System.Buffer.BlockCopy创建字节数组- 0.2500048秒 IEnumerable<字节>使用c# yield运算符- 0.0625012秒 IEnumerable<byte> using LINQ's Concat<> - 0.0781265秒
我将每个数组的大小增加到1000个元素,并重新运行测试:
使用System.Array.Copy创建字节数组- 1.0781457秒 使用System.Buffer.BlockCopy创建字节数组1.0156445秒 IEnumerable<字节>使用c# yield运算符- 0.0625012秒 IEnumerable<byte> using LINQ's Concat<> - 0.0781265秒
最后,我将每个数组的大小增加到100万个元素,并重新运行测试,每个循环只执行4000次:
使用System.Array.Copy创建字节数组- 13.4533833秒 使用System.Buffer.BlockCopy创建字节数组 IEnumerable<字节>使用c# yield操作符- 0秒 IEnumerable<字节>使用LINQ的Concat<> - 0秒
所以,如果你需要一个新的字节数组,使用
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<byte>,肯定更喜欢LINQ的Concat<>方法。它只比c#的yield操作符稍慢,但更简洁、更优雅。
IEnumerable<byte> rv = 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关于后续数据结构迭代(字节数组vs. IEnumerable<byte>)的观点,我重新运行了最后一次计时测试(100万个元素,4000次迭代),添加了一个循环,每次迭代整个数组:
使用System.Array.Copy新建字节数组- 78.20550510秒 使用System.Buffer.BlockCopy创建字节数组77.89261900秒 IEnumerable<字节>使用c# yield运算符- 551.7150161秒 IEnumerable<byte> using LINQ's Concat<> - 448.1804799秒
重点是,理解创建结果数据结构和使用结果数据结构的效率是非常重要的。仅仅关注创造的效率可能会忽略与使用相关的低效率。荣誉,乔恩。
我以Matt的LINQ为例,进一步提高了代码的洁净度:
byte[] rv = a1.Concat(a2).Concat(a3).ToArray();
在我的例子中,数组很小,所以我不关心性能。
Concat是正确答案,但出于某种原因,手摇的东西得到了最多的选票。如果你喜欢这个答案,也许你会更喜欢这个通解:
IEnumerable<byte> Combine(params byte[][] arrays)
{
foreach (byte[] a in arrays)
foreach (byte b in a)
yield return b;
}
这可以让你做以下事情:
byte[] c = Combine(new byte[] { 0, 1, 2 }, new byte[] { 3, 4, 5 }).ToArray();
推荐文章
- 实体框架核心:在上一个操作完成之前,在此上下文中开始的第二个操作
- 如何为构造函数定制Visual Studio的私有字段生成快捷方式?
- 如何使用JSON确保字符串是有效的JSON。网
- 使用C返回一个数组
- AppSettings从.config文件中获取值
- 通过HttpClient向REST API发布一个空体
- 如何检查IEnumerable是否为空或空?
- 自动化invokerrequired代码模式
- 在c#代码中设置WPF文本框的背景颜色
- 在c#中,什么是单子?
- c#和Java中的泛型有什么不同?和模板在c++ ?
- 向对象数组添加属性
- c#线程安全快速(est)计数器
- 如何将此foreach代码转换为Parallel.ForEach?
- 如何分裂()一个分隔字符串到一个列表<字符串>