C#에서 두 개 이상의 바이트 배열을 결합하는 가장 좋은 방법
C#에 있는 3바이트 배열을 하나로 결합해야 합니다.이 작업을 완료하는 가장 효율적인 방법은 무엇입니까?
기본 유형(바이트 포함)의 경우 를 대신 사용합니다. 더 빠릅니다.
저는 각각 10바이트씩 3개의 배열을 사용하여 100만 번 실행된 루프에서 각각의 제안된 방법의 시간을 측정했습니다.결과는 다음과 같습니다.
- 다음을 사용하여 새 바이트 배열 만들기
System.Array.Copy
.2187556ppm - 다음을 사용하여 새 바이트 배열 만들기
System.Buffer.BlockCopy
.1406286ppm - C# 항복 연산자를 사용한 IEnumberable <byte> - 0.0781270초
- LINQ의 Concat을 사용한 IEnumberable<byte> - 0.0781270초
각 어레이의 크기를 100개 요소로 늘리고 테스트를 다시 실행했습니다.
- 다음을 사용하여 새 바이트 배열 만들기
System.Array.Copy
.2812554초 - 다음을 사용하여 새 바이트 배열 만들기
System.Buffer.BlockCopy
.2500048초 - C# 항복 연산자를 사용한 IEnumberable <byte> - 0.0625012초
- LINQ의 Concat을 사용한 IEnumberable<byte> - 0.0781265초
각 어레이의 크기를 1000개 요소로 늘리고 테스트를 다시 실행했습니다.
- 다음을 사용하여 새 바이트 배열 만들기
System.Array.Copy
.0781457㎜ - 다음을 사용하여 새 바이트 배열 만들기
System.Buffer.BlockCopy
.0156445ppm - C# 항복 연산자를 사용한 IEnumberable <byte> - 0.0625012초
- LINQ의 Concat을 사용한 IEnumberable<byte> - 0.0781265초
마지막으로 각 어레이의 크기를 1백만 개의 요소로 늘리고 테스트를 다시 실행하여 각 루프를 4,000번만 실행했습니다.
- 다음을 사용하여 새 바이트 배열 만들기
System.Array.Copy
.45333mx - 다음을 사용하여 새 바이트 배열 만들기
System.Buffer.BlockCopy
.1096267초 - C# 양보 연산자를 사용한 IEnumberable <byte> - 0초
- LINQ의 Concat을 사용한 IEnumberable<byte> - 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# 수율 연산자보다 약간 느리지만 보다 간결하고 우아합니다.
IEnumerable<byte> rv = a1.Concat(a2).Concat(a3);
. 3사용하는 에는 .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;
후속 데이터 구조(바이트 배열 대IEnumberable<byte>), 마지막 타이밍 테스트(1백만 개 요소, 4,000번 반복)를 다시 실행하여 각 패스로 전체 어레이에서 반복되는 루프를 추가했습니다.
- 다음을 사용하여 새 바이트 배열 만들기
System.Array.Copy
.20550510초 - 다음을 사용하여 새 바이트 배열 만들기
System.Buffer.BlockCopy
.89261900초 - C# 항복 연산자를 사용한 IEnumberable <byte> - 551.7150161초
- LINQ의 Concat을 사용한 IEnumberable<byte> - 448.1804799초
중요한 것은 데이터 구조의 생성과 사용의 효율성을 이해하는 것이 매우 중요하다는 것입니다.단순히 창작의 효율성에 초점을 맞추는 것만으로도 사용과 관련된 비효율성을 간과할 수 있습니다.칭찬해, 존.
제가 보기에 많은 답변들이 명시된 요구 사항을 무시하고 있는 것 같습니다.
- 결과는 바이트 배열이어야 합니다.
- 가능한 한 효율적이어야 합니다.
두 합니다. 즉, "LINQ"가 있는 모든 는 제외됩니다.yield
전체 시퀀스를 반복하지 않고는 최종 크기를 얻는 것이 불가능합니다.
물론 이러한 요구사항이 실제 요구사항이 아니라면 LINQ는 완벽하게 좋은 솔루션이 될 수 있습니다.IList<T>
을 원하는지 있다고 하지만 슈퍼덤벨은 그가 무엇을 원하는지 알고 있다고 생각합니다.
(편집: 저는 방금 다른 생각을 했습니다.배열의 복사본을 만드는 것과 게으르게 읽는 것 사이에는 큰 의미적 차이가 있습니다." 배열 중 에서 "" 후 생각해 .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;
}
또는 단일 IE 번호가 필요한 경우 C# 2.0 수율 연산자를 사용하는 것이 좋습니다.
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;
}
사실 Concat을 사용할 때 몇 가지 문제가 발생했습니다.(1,000만 개의 어레이를 보유한 상태에서 실제로 충돌했습니다.)
다음은 간단하고 간편하며 충돌 없이 충분히 작동하며, 3개가 아닌 모든 수의 어레이에서 작동합니다(LINQ 사용).
public static byte[] ConcatByteArrays(params byte[][] arrays)
{
return arrays.SelectMany(x => x).ToArray();
}
메모리 스트림 수업은 저에게 이 일을 꽤 잘 해줍니다.버퍼 클래스를 메모리 스트림만큼 빠르게 실행할 수 없습니다.
using (MemoryStream ms = new MemoryStream())
{
ms.Write(BitConverter.GetBytes(22),0,4);
ms.Write(BitConverter.GetBytes(44),0,4);
ms.ToArray();
}
public static byte[] Concat(params byte[][] arrays) {
using (var mem = new MemoryStream(arrays.Sum(a => a.Length))) {
foreach (var array in arrays) {
mem.Write(array, 0, array.Length);
}
return mem.ToArray();
}
}
public static bool MyConcat<T>(ref T[] base_arr, ref T[] add_arr)
{
try
{
int base_size = base_arr.Length;
int size_T = System.Runtime.InteropServices.Marshal.SizeOf(base_arr[0]);
Array.Resize(ref base_arr, base_size + add_arr.Length);
Buffer.BlockCopy(add_arr, 0, base_arr, base_size * size_T, add_arr.Length * size_T);
}
catch (IndexOutOfRangeException ioor)
{
MessageBox.Show(ioor.Message);
return false;
}
return true;
}
제네릭을 사용하여 배열을 결합할 수 있습니다.다음 코드는 3개의 배열로 쉽게 확장할 수 있습니다.이렇게 하면 다른 유형의 어레이에 대해 코드를 복제할 필요가 없습니다.위의 답변 중 일부는 제가 보기에 너무 복잡해 보입니다.
private static T[] CombineTwoArrays<T>(T[] a1, T[] a2)
{
T[] arrayCombined = new T[a1.Length + a2.Length];
Array.Copy(a1, 0, arrayCombined, 0, a1.Length);
Array.Copy(a2, 0, arrayCombined, a1.Length, a2.Length);
return arrayCombined;
}
/// <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();
다음은 @John Skeet가 제공한 답변의 일반화입니다.기본적으로 동일하며 바이트뿐만 아니라 모든 유형의 어레이에 사용할 수 있습니다.
public static T[] Combine<T>(T[] first, T[] second)
{
T[] ret = new T[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 T[] Combine<T>(T[] first, T[] second, T[] third)
{
T[] ret = new T[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 T[] Combine<T>(params T[][] arrays)
{
T[] ret = new T[arrays.Sum(x => x.Length)];
int offset = 0;
foreach (T[] data in arrays)
{
Buffer.BlockCopy(data, 0, ret, offset, data.Length);
offset += data.Length;
}
return ret;
}
바이트 배열 목록을 전달하기만 하면 이 함수는 바이트 배열(병합)을 반환합니다.이것이 제가 생각하는 최고의 해결책입니다 :).
public static byte[] CombineMultipleByteArrays(List<byte[]> lstByteArray)
{
using (var ms = new MemoryStream())
{
using (var doc = new iTextSharp.text.Document())
{
using (var copy = new PdfSmartCopy(doc, ms))
{
doc.Open();
foreach (var p in lstByteArray)
{
using (var reader = new PdfReader(p))
{
copy.AddDocument(reader);
}
}
doc.Close();
}
}
return ms.ToArray();
}
}
콩캣이 정답이지만, 어떤 이유에서인지 가장 많은 표를 얻는 것은 조작된 것입니다.이러한 답변이 마음에 든다면 더욱 일반적인 솔루션을 원할 것입니다.
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();
언급URL : https://stackoverflow.com/questions/415291/best-way-to-combine-two-or-more-byte-arrays-in-c-sharp
'programing' 카테고리의 다른 글
Objective-C에서 NSRay를 NSString으로 변환 (0) | 2023.05.28 |
---|---|
bash를 강제로 파일에서 로드된 문자열의 변수 확장 (0) | 2023.05.28 |
쿼리 계획에서 "비트맵 힙 검사"란 무엇입니까? (0) | 2023.05.23 |
Collections.defaultdict 차이와 일반 dict (0) | 2023.05.23 |
VBA 메시지 상자에서 선택 가능한 텍스트 (0) | 2023.05.23 |