2011-02-02 18 views
9

Tôi đang tạo một số mảng byte cần được nối với nhau để tạo một mảng byte lớn - tôi không muốn sử dụng byte [] ở tất cả nhưng không có lựa chọn nào ở đây. ..Ghép nối danh sách C# của byte []

Tôi đang thêm từng danh sách vào Danh sách khi tạo, vì vậy tôi chỉ phải thực hiện kết nối khi tôi có tất cả byte [], nhưng câu hỏi của tôi là, cách tốt nhất để thực sự là gì làm điều này?

Khi tôi có danh sách có số byte không xác định và tôi muốn kết hợp chúng lại với nhau.

Cảm ơn.

Trả lời

18
listOfByteArrs.SelectMany(byteArr=>byteArr).ToArray() 

Mã trên sẽ nối chuỗi trình tự byte thành một chuỗi - và lưu kết quả vào một mảng.

Mặc dù có thể đọc được, đây không phải là tối đa hiệu quả - nó không làm cho việc sử dụng thực tế là bạn đã biết chiều dài của mảng byte kết quả và do đó có thể tránh được tự động mở rộng .ToArray() thực hiện điều đó nhất thiết liên quan đến nhiều phân bổ và array- bản sao. Hơn nữa, SelectMany được thực hiện theo vòng lặp; điều này có nghĩa là rất nhiều + rất nhiều cuộc gọi giao diện khá chậm. Tuy nhiên, đối với các kích thước tập dữ liệu nhỏ-ish thì điều này không quan trọng.

Nếu bạn cần triển khai nhanh hơn bạn có thể làm như sau:

var output = new byte[listOfByteArrs.Sum(arr=>arr.Length)]; 
int writeIdx=0; 
foreach(var byteArr in listOfByteArrs) { 
    byteArr.CopyTo(output, writeIdx); 
    writeIdx += byteArr.Length; 
} 

hoặc như Martinho gợi ý:

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); 

Một số timings:

var listOfByteArrs = Enumerable.Range(1,1000) 
    .Select(i=>Enumerable.Range(0,i).Select(x=>(byte)x).ToArray()).ToList(); 

Sử dụng ngắn phương pháp để ghép các 500500 byte này mất 15ms, sử dụng fa phương pháp st mất 0,5ms trên máy tính của tôi - YMMV, và lưu ý rằng đối với nhiều ứng dụng cả hai đều nhanh hơn đủ ;-).

Cuối cùng, bạn có thể thay thế Array.CopyTo với staticArray.Copy, cấp thấp Buffer.BlockCopy, hoặc một MemoryStream với một bộ đệm preallocated trở lại - đây là tất cả thực hiện khá nhiều hệt các bài kiểm tra của tôi (x64 .NET 4.0).

+4

Mặc dù ngắn gọn và rõ ràng, lưu ý rằng mã này rất chậm so với giải pháp truyền thống. Nếu nó đủ nhanh, tuyệt vời, nhưng nó có thể không đủ nhanh. –

+0

Đó là "giải pháp truyền thống"? – amalgamate

+0

Giải pháp "truyền thống" có thể là thủ công, được lồng ghép cho các vòng lặp. Đó là khoảng ba lần chậm hơn so với các giải pháp dựa trên khối bản sao, nhưng vẫn nhanh hơn 10 lần so với 'SelectMany'. –

-1

hmm khoảng list.addrange?

+0

lý do cho -1? – Fredou

+0

AddRange có chuyển đổi một List thành một byte [] không? Số –

2

ghi tất cả vào MemoryStream thay vì danh sách. sau đó gọi MemoryStream.ToArray(). Hoặc khi bạn có danh sách, đầu tiên tóm tắt tất cả các độ dài mảng byte, tạo một mảng byte mới với tổng chiều dài và sao chép từng mảng sau mảng cuối cùng trong mảng lớn.

0

Thay vì lưu trữ từng mảng byte thành List<byte[]>, bạn có thể thay chúng trực tiếp vào List<byte>, sử dụng phương thức AddRange cho từng mảng.

1

Sử dụng 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(); 

Có lẽ giải pháp nhanh hơn sẽ được (không khai báo mảng trả trước):

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; 
     } 
    } 
} 

Nó có vẻ như trên sẽ lặp mỗi mảng chỉ một lần.

+0

Điều này có vẻ như nó có thể làm việc nhờ, tôi sẽ cho nó một đi. –

+2

Lưu ý rằng giải pháp này là O (n^2) trong số mảng byte. (Bạn có thấy lý do tại sao? Gợi ý: các nhà khai thác chuỗi là * lười biếng *.) Bạn có thể làm tốt hơn thế. Bạn có thể tìm thấy một giải pháp tuyến tính trong số mảng byte không? –

+0

@Eric: cảm ơn! Nó không phải là hiển nhiên đối với tôi rằng giải pháp là O (n^2). Điều gì sẽ xảy ra nếu tôi sử dụng phương thức riêng để tạo thành số lượng byte? Tôi đã cập nhật câu trả lời. –

4

Đây là giải pháp dựa trên số Andrew Bezzubfejesjoco's answers, phân bổ trước tất cả bộ nhớ cần thiết lên phía trước. Điều này cho biết thời gian sử dụng bộ nhớ Θ (N) và thời gian Θ (N) (N là tổng số byte).

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;