Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/313.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
连接字节[]的C#列表_C#_List_Bytearray_Concatenation - Fatal编程技术网

连接字节[]的C#列表

连接字节[]的C#列表,c#,list,bytearray,concatenation,C#,List,Bytearray,Concatenation,我正在创建几个字节数组,它们需要连接在一起才能创建一个大字节数组-我不想使用字节[],但在这里没有选择 在创建它们时,我会将每一个都添加到一个列表中,所以我只需要在获得所有字节[]后进行连接,但我的问题是,实际执行此操作的最佳方式是什么 当我有一个包含未知字节数[]的列表时,我想将它们全部合并在一起 谢谢 listOfByteArrs.SelectMany(byteArr=>byteArr).ToArray() 上面的代码将字节序列连接成一个序列,并将结果存储在数组中 虽然可读,但这并不

我正在创建几个字节数组,它们需要连接在一起才能创建一个大字节数组-我不想使用字节[],但在这里没有选择

在创建它们时,我会将每一个都添加到一个列表中,所以我只需要在获得所有字节[]后进行连接,但我的问题是,实际执行此操作的最佳方式是什么

当我有一个包含未知字节数[]的列表时,我想将它们全部合并在一起

谢谢

listOfByteArrs.SelectMany(byteArr=>byteArr).ToArray()
上面的代码将字节序列连接成一个序列,并将结果存储在数组中

虽然可读,但这并不是最有效的—它没有利用您已经知道结果字节数组的长度这一事实,因此可以避免动态扩展的
.ToArray()
实现,该实现必然涉及多个分配和数组副本。此外,
SelectMany
以迭代器的形式实现;这意味着大量的接口调用非常缓慢。然而,对于较小的ish数据集大小来说,这不太可能重要

如果需要更快的实施,可以执行以下操作:

var output = new byte[listOfByteArrs.Sum(arr=>arr.Length)];
int writeIdx=0;
foreach(var byteArr in listOfByteArrs) {
    byteArr.CopyTo(output, writeIdx);
    writeIdx += byteArr.Length;
}
或者正如Martinho所建议的:

var output = new byte[listOfByteArrs.Sum(arr => arr.Length)];
using(var stream = new MemoryStream(output))
    foreach (var bytes in listOfByteArrs)
        stream.Write(bytes, 0, bytes.Length);
一些时间安排:

var listOfByteArrs = Enumerable.Range(1,1000)
    .Select(i=>Enumerable.Range(0,i).Select(x=>(byte)x).ToArray()).ToList();
使用short方法连接这些500500字节需要15毫秒,在我的机器上使用fast方法需要0.5毫秒-YMMV,并且注意,对于许多应用程序,这两种方法都足够快;-)


最后,您可以将
数组.CopyTo
替换为
静态
数组.Copy
、低级
缓冲区.BlockCopy
、或
内存流
替换为预分配的后缓冲区-这些都在我的测试中执行得非常相同(x64.NET 4.0).

嗯,怎么样?

将它们全部写入内存流而不是列表。然后调用MemoryStream.ToArray()。或者,当您有了列表后,首先汇总所有字节数组长度,创建一个新的字节数组,使用总长度,并在大数组中的最后一个之后复制每个数组。

而不是将每个字节数组存储到
列表中,您可以使用每个字节数组的方法将它们直接添加到
列表中。

使用Linq:

    List<byte[]> list = new List<byte[]>();
    list.Add(new byte[] { 1, 2, 3, 4 });
    list.Add(new byte[] { 1, 2, 3, 4 });
    list.Add(new byte[] { 1, 2, 3, 4 });

    IEnumerable<byte> result = Enumerable.Empty<byte>();

    foreach (byte[] bytes in list)
    {
        result = result.Concat(bytes);
    }

    byte[] newArray = result.ToArray();
List List=新列表();
添加(新字节[]{1,2,3,4});
添加(新字节[]{1,2,3,4});
添加(新字节[]{1,2,3,4});
IEnumerable结果=Enumerable.Empty();
foreach(列表中的字节[]字节)
{
结果=result.Concat(字节);
}
byte[]newArray=result.ToArray();
也许更快的解决方案是(不预先声明阵列):

IEnumerable bytesEnumerable=GetBytesFromList(列表);
byte[]newArray=bytesEnumerable.ToArray();
私有静态IEnumerable GetBytesFromList(IEnumerable列表)
{
foreach(列表中的IEnumerable元素)
{
foreach(元素中的T元素)
{
收益-收益要素;
}
}
}

上面似乎只会对每个数组迭代一次。

这里有一个基于和的解决方案,预先分配所有需要的内存。这将产生Θ(N)内存使用率和Θ(N)时间(N为总字节数)


虽然简短明了,但请注意,与传统解决方案相比,此代码速度非常慢。如果它足够快,很好,但可能不够快。哪种是“传统解决方案”?传统解决方案可能是手动的,嵌套循环。这大约比基于块拷贝的解决方案慢三倍,但仍然比
SelectMany
快10倍。AddRange是否将列表转换为字节[]?否。请注意,此解决方案的字节数组数为O(n^2)。(你知道为什么吗?提示:序列操作符是懒惰的。)你可以做得更好。你能找到一个字节数组数呈线性的解决方案吗?@Eric:谢谢!对我来说,答案是O(n^2)并不明显。如果我使用单独的方法来形成可枚举的字节呢?我更新了答案。懒惰和它有什么关系?非惰性实现也应该是O(N^2)。相反,您可能有一个延迟序列和O(N)性能。问题是所需的接口换行-您需要连续换行枚举数-您不能声明延续。这不是一个完全公平的比较,但在Haskell概念上相似的代码中,例如lazy和O(N)。事实上。现在概括一下。这不必是列表;它可以是IEnumerable,因为除了它是可枚举的之外,您不使用List的任何属性。同样,它也不必是字节[];您不使用字节或数组的属性。都是序列!在C#4中,您可以说IEnumerable flant(IEnumerable items){foreach(项目中的var序列)foreach(序列中的T T)产生返回T;}并完成它。(这取决于IEnumerable的协方差,因此它只在C#4中起作用;有一些方法可以使它在C#3中使用更多类型参数。)当然,您可以进一步推广到IEnumerable展平(IEnumerable项,Func选择器){foreach(项中的T项)foreach(选择器(项中的R结果))产生返回结果;},你刚刚发明了很多;此方法已在序列运算符库中。
IEnumerable<byte> bytesEnumerable = GetBytesFromList(list);

byte[] newArray = bytesEnumerable.ToArray();

private static IEnumerable<T> GetBytesFromList<T>(IEnumerable<IEnumerable<T>> list)
{
    foreach (IEnumerable<T> elements in list)
    {
        foreach (T element in elements)
        {
            yield return element;
        }
    }
}
byte[] result = new byte[list.Sum(a => a.Length)];
using(var stream = new MemoryStream(result))
{
    foreach (byte[] bytes in list)
    {
        stream.Write(bytes, 0, bytes.Length);
    }
}
return result;