วิธีที่ดีที่สุดในการรวมอาร์เรย์สองตัวหรือมากกว่าใน C #


238

ฉันมีอาร์เรย์ 3 ไบต์ใน C # ที่ฉันต้องรวมเข้าเป็นหนึ่งเดียว อะไรจะเป็นวิธีที่มีประสิทธิภาพที่สุดในการทำภารกิจนี้ให้สำเร็จ


3
คุณต้องการอะไรเป็นพิเศษ? คุณกำลังรวมกันของอาร์เรย์หรือคุณกำลังเก็บอินสแตนซ์หลาย ๆ ค่าที่เหมือนกันหรือไม่? คุณต้องการเรียงลำดับรายการหรือคุณต้องการรักษาการเรียงลำดับในอาร์เรย์เริ่มต้นหรือไม่ คุณกำลังมองหาประสิทธิภาพในความเร็วหรือในบรรทัดของรหัส?
jason

รักมากที่สุดขึ้นอยู่กับความต้องการของคุณ
Ady

7
ถ้าคุณมีความสามารถที่จะใช้ LINQ แล้วคุณก็สามารถใช้Concatวิธีการ:IEnumerable<byte> arrays = array1.Concat(array2).Concat(array3);
casperOne

1
โปรดลองคำถามของคุณให้ชัดเจนยิ่งขึ้น คำถามที่คลุมเครือนี้ทำให้เกิดความสับสนมากในหมู่คนเหล่านั้นดีพอที่จะตอบคำถามของคุณ
Drew Noakes

คำตอบ:


326

สำหรับรูปแบบดั้งเดิม (รวม bytes) ใช้แทนSystem.Buffer.BlockCopy System.Array.Copyมันเร็วกว่า

ฉันหมดเวลาแต่ละวิธีที่แนะนำในการวนซ้ำ 1 ล้านครั้งโดยใช้ 3 อาร์เรย์ 10 ไบต์ นี่คือผลลัพธ์:

  1. ใช้ Byte Array ใหม่System.Array.Copy - 0.2187556 วินาที
  2. ใช้ Byte Array ใหม่System.Buffer.BlockCopy - 0.1406286 วินาที
  3. IE จำนวน <byte> ที่ใช้ตัวดำเนินการผลตอบแทน C # - 0.0781270 วินาที
  4. IEnumerable <byte> โดยใช้ Concat <> ของ LINQ - 0.0781270 วินาที

ฉันเพิ่มขนาดของแต่ละอาร์เรย์เป็น 100 องค์ประกอบและทำการทดสอบอีกครั้ง:

  1. ใช้ Byte Array ใหม่System.Array.Copy - 0.2812554 วินาที
  2. ใช้ Byte Array ใหม่System.Buffer.BlockCopy - 0.2500048 วินาที
  3. IE จำนวน <byte> ที่ใช้ตัวดำเนินการผลตอบแทน C # - 0.0625012 วินาที
  4. IEnumerable <byte> โดยใช้ Concat <> ของ LINQ - 0.0781265 วินาที

ฉันเพิ่มขนาดของแต่ละอาร์เรย์เป็น 1,000 อิลิเมนต์และทำการทดสอบอีกครั้ง:

  1. ใช้ Byte Array ใหม่System.Array.Copy - 1.0781457 วินาที
  2. ใช้ Byte Array ใหม่System.Buffer.BlockCopy - 1.0156445 วินาที
  3. IE จำนวน <byte> ที่ใช้ตัวดำเนินการผลตอบแทน C # - 0.0625012 วินาที
  4. IEnumerable <byte> โดยใช้ Concat <> ของ LINQ - 0.0781265 วินาที

ในที่สุดฉันเพิ่มขนาดของแต่ละอาร์เรย์เป็น 1 ล้านองค์ประกอบและเรียกใช้การทดสอบอีกครั้งเรียกใช้แต่ละวงเพียง 4000 ครั้ง:

  1. ใช้ Byte Array ใหม่System.Array.Copy - 13.4533833 วินาที
  2. ใช้ Byte Array ใหม่System.Buffer.BlockCopy - 13.1096267 วินาที
  3. IE จำนวน <byte> โดยใช้ตัวดำเนินการผลตอบแทน C # - 0 วินาที
  4. IE จำนวน <byte> โดยใช้ Concat <> ของ LINQ - 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);

หากคุณมีอาร์เรย์จำนวนเท่าใดและใช้. 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 <byte>) ฉันทำการทดสอบการจับเวลาครั้งสุดท้ายอีกครั้ง (1 ล้านองค์ประกอบ 4,000 การวนซ้ำ) เพิ่มการวนซ้ำที่เต็มไปด้วยอาร์เรย์ทั้งหมด ผ่าน:

  1. ใช้ Byte Array ใหม่System.Array.Copy - 78.20550510 วินาที
  2. ใช้ Byte Array ใหม่System.Buffer.BlockCopy - 77.89261900 วินาที
  3. IE จำนวน <byte> ที่ใช้ตัวดำเนินการผลตอบแทน C # - 551.7150161 วินาที
  4. IEnumerable <byte> โดยใช้ Concat <> ของ LINQ - 448.1804799 วินาที

ประเด็นก็คือมันสำคัญมากที่จะเข้าใจประสิทธิภาพของการสร้างและการใช้โครงสร้างข้อมูลที่เกิดขึ้น เพียงแค่มุ่งเน้นไปที่ประสิทธิภาพของการสร้างอาจมองข้ามความไร้ประสิทธิภาพที่เกี่ยวข้องกับการใช้งาน รุ่งโรจน์จอน


61
แต่คุณจะแปลงให้เป็นอาเรย์ในตอนท้ายตามที่คำถามต้องการหรือไม่ ถ้าไม่ใช่แน่นอนมันเร็วกว่า - แต่ก็ไม่ได้ทำตามข้อกำหนด
Jon Skeet

18
Re: แมตต์เดวิส - มันไม่สำคัญว่าถ้า "ความต้องการ" ของคุณจำเป็นต้องเปิด IEnumerable เป็นอาร์เรย์ - ทุกสิ่งที่ต้องการของคุณจำเป็นที่จะต้องเป็นว่าผลที่เป็นจริงที่ใช้ในแฟชั่นบาง เหตุผลที่การทดสอบประสิทธิภาพของคุณบน IEnumerable นั้นต่ำมากเพราะคุณไม่ได้ทำอะไรเลย ! LINQ จะไม่ทำงานใด ๆ จนกว่าคุณจะพยายามใช้ผลลัพธ์ ด้วยเหตุนี้ฉันจึงพบว่าคำตอบของคุณไม่ถูกต้องและอาจทำให้ผู้อื่นใช้งาน LINQ เมื่อพวกเขาไม่ควรทำอย่างนั้นถ้าพวกเขาสนใจเรื่องประสิทธิภาพ
csauve

12
ฉันอ่านคำตอบทั้งหมดรวมถึงการอัปเดตของคุณ ฉันรู้ว่าฉันมาร่วมงานกับพรรคปลาย แต่คำตอบคือไม่มีการลดความเข้าใจผิดและครึ่งแรกเป็นเหตุเท็จ
csauve

14
ทำไมคำตอบที่มีข้อมูลที่ผิดและทำให้เข้าใจผิดเป็นคำตอบที่ได้รับการโหวตแล้วและได้รับการแก้ไขให้เป็นโมฆะโดยสมบูรณ์หลังจากที่มีคน (Jon Skeet) ชี้ให้เห็นว่ามันไม่ได้ตอบคำถาม OPs ด้วย?
MrCC

3
คำตอบที่ทำให้เข้าใจผิด แม้แต่ฉบับก็ยังไม่ตอบคำถาม
Serge Profafilecebook

154

คำตอบหลายข้อดูเหมือนจะทำให้ฉันเพิกเฉยต่อข้อกำหนดที่ระบุไว้:

  • ผลลัพธ์ควรเป็นอาร์เรย์ไบต์
  • ควรมีประสิทธิภาพที่สุด

ทั้งสองร่วมกันออกกฎเรียงลำดับ LINQ ไบต์ - สิ่งที่yieldจะทำให้เป็นไปไม่ได้ที่จะได้รับขนาดสุดท้ายโดยไม่ต้องวนซ้ำผ่านลำดับทั้งหมด

หากสิ่งเหล่านั้นไม่ใช่ข้อกำหนดที่แท้จริงของหลักสูตร LINQ อาจเป็นทางออกที่ดีอย่างสมบูรณ์ (หรือIList<T>การนำไปใช้) อย่างไรก็ตามฉันจะสมมติว่า 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 Davis

1
@ แมท: ใช่การเสนอทางเลือกเป็นสิ่งที่ดี - แต่ก็คุ้มค่าที่จะอธิบายว่าพวกเขาเป็นทางเลือกมากกว่าที่จะผ่านพวกเขาไปเป็นคำตอบของคำถามที่ถูกถาม (ฉันไม่ได้บอกว่าคุณทำอย่างนั้น - คำตอบของคุณดีมาก)
Jon Skeet

4
(ถึงแม้ว่าผมจะคิดว่ามาตรฐานประสิทธิภาพของคุณควรจะแสดงเวลาที่จะไปผ่านผลทั้งหมดในแต่ละกรณีเกินไปที่จะหลีกเลี่ยงการให้การประเมินผลขี้เกียจได้เปรียบที่ไม่เป็นธรรม.)
จอนสกีต

1
แม้จะไม่มีการประชุมความต้องการของ "ผลลัพธ์ต้องเป็นอาร์เรย์" เพียงแค่ตอบสนองความต้องการของ "ผลลัพธ์ที่ต้องใช้ในบางแฟชั่น" จะทำให้ LINQ ไม่เหมาะสม ฉันคิดว่าความต้องการที่จะสามารถใช้ผลลัพธ์ควรเป็นนัย!
csauve

2
@andleer: นอกเหนือจากสิ่งอื่นแล้ว Buffer.BlockCopy ใช้งานได้กับประเภทดั้งเดิมเท่านั้น
Jon Skeet

44

ฉันใช้ตัวอย่าง LINQ ของ Matt อีกหนึ่งขั้นตอนเพื่อความสะอาดของโค้ด:

byte[] rv = a1.Concat(a2).Concat(a3).ToArray();

ในกรณีของฉันอาร์เรย์มีขนาดเล็กดังนั้นฉันจึงไม่กังวลเกี่ยวกับประสิทธิภาพ


3
วิธีแก้ปัญหาสั้นและง่ายการทดสอบประสิทธิภาพจะยอดเยี่ยม!
เซบาสเตียน

3
นี่เป็นที่ชัดเจนอ่านง่ายไม่ต้องใช้ห้องสมุด / ผู้ช่วยเหลือภายนอกและในแง่ของเวลาในการพัฒนานั้นค่อนข้างมีประสิทธิภาพ ยอดเยี่ยมเมื่อประสิทธิภาพของรันไทม์ไม่สำคัญ
binki

28

หากคุณต้องการอาร์เรย์ไบต์ใหม่ให้ใช้สิ่งต่อไปนี้:

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:

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

ฉันได้ทำสิ่งที่คล้ายกับตัวเลือกที่ 2 ของคุณเพื่อรวมกระแสข้อมูลขนาดใหญ่ทำงานเหมือนมีเสน่ห์ :)
Greg D

2
ตัวเลือกที่สองนั้นยอดเยี่ยม +1
R. Martinho Fernandes

11

ที่จริงฉันเจอปัญหาบางอย่างกับการใช้ Concat ... (กับอาร์เรย์ใน 10 ล้านมันล้มเหลวจริงๆ)

ฉันพบว่าสิ่งต่อไปนี้นั้นง่ายเรียบง่ายและทำงานได้ดีพอโดยไม่ต้องทำอะไรเลยและมันใช้ได้กับอาร์เรย์จำนวนเท่าใดก็ได้ (ไม่ใช่แค่สาม) (ใช้ LINQ):

public static byte[] ConcatByteArrays(params byte[][]  arrays)
{
    return arrays.SelectMany(x => x).ToArray();
}

6

คลาส memorystream ทำงานนี้ค่อนข้างดีสำหรับฉัน ฉันไม่สามารถทำให้คลาสบัฟเฟอร์ทำงานได้เร็วเท่ากับ memorystream

using (MemoryStream ms = new MemoryStream())
{
  ms.Write(BitConverter.GetBytes(22),0,4);
  ms.Write(BitConverter.GetBytes(44),0,4);
  ms.ToArray();
}

3
ตามที่ qwe กล่าวฉันได้ทำการทดสอบในวง 10,000,000 ครั้งและ MemoryStream ออกมา 290% ช้ากว่า Buffer.BlockCopy
esac

ในบางกรณีคุณอาจทำการวนซ้ำของอาร์เรย์โดยไม่ต้องรู้ล่วงหน้าเกี่ยวกับความยาวของอาร์เรย์แต่ละตัว วิธีนี้ใช้ได้ดีในสถานการณ์นี้ BlockCopy อาศัยการมีอาร์เรย์ปลายทางที่ถูกสร้างไว้ล่วงหน้า
Sentinel

ดังที่ @Sentinel กล่าวว่าคำตอบนี้เหมาะสำหรับฉันเพราะฉันไม่รู้ขนาดของสิ่งที่ฉันต้องเขียนและทำให้ฉันทำสิ่งต่าง ๆ ได้อย่างหมดจด นอกจากนี้ยังเล่นได้ดีกับ [ReadOnly] Span <byte> ของ. NET Core 3!
น้ำ

หากคุณเริ่มต้น MemoryStream ด้วยขนาดสุดท้ายขนาดจะไม่ถูกสร้างขึ้นใหม่และจะเร็วขึ้น @ esac
Tono Nam

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

น่าเสียดายที่นี่ไม่สามารถใช้ได้กับทุกประเภท Marshal.SizeOf () จะไม่สามารถส่งคืนขนาดได้หลายประเภท (ลองใช้วิธีนี้กับอาร์เรย์ของสตริงและคุณจะเห็นข้อยกเว้น "Type 'System.String' ไม่สามารถ marshaled เป็นโครงสร้างที่ไม่มีการจัดการไม่มีขนาดที่มีความหมายหรือ offset สามารถคำนวณได้ "คุณสามารถลอง จำกัด พารามิเตอร์ type ให้กับประเภทการอ้างอิงเท่านั้น (โดยการเพิ่มwhere T : struct) แต่ - ไม่ใช่การเป็นผู้เชี่ยวชาญในอวัยวะภายในของ CLR - ฉันไม่สามารถพูดได้ว่าคุณอาจได้รับข้อยกเว้นใน structs บางอย่างเช่นกัน (เช่นหากมีเขตข้อมูลประเภทการอ้างอิง)
Daniel Scott

2
    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();
        }
    }

คุณอาจตอบได้ดีกว่าถ้าคุณโพสต์คำอธิบายเล็ก ๆ น้อย ๆ เกี่ยวกับตัวอย่างโค้ดนี้
หยุด

1
มันเชื่อมต่ออาร์เรย์ของอาร์เรย์ไบต์เป็นอาร์เรย์ไบต์ขนาดใหญ่หนึ่งรายการ (เช่นนี้): [1,2,3] + [4,5] + [6,7] ==> [1,2,3,4,5 , 6,7]
Peter Ertl

1

สามารถใช้ข้อมูลทั่วไปเพื่อรวมอาร์เรย์ รหัสต่อไปนี้สามารถขยายได้อย่างง่ายดายถึงสามอาร์เรย์ วิธีนี้คุณไม่จำเป็นต้องทำสำเนารหัสสำหรับอาร์เรย์ประเภทอื่น คำตอบข้างต้นบางคำดูเหมือนซับซ้อนเกินไปสำหรับฉัน

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

0

ต่อไปนี้เป็นคำอธิบายทั่วไปของคำตอบที่ @Jon 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;
}

3
อันตราย! วิธีการเหล่านี้จะไม่ทำงานกับประเภทอาร์เรย์ใด ๆ ที่มีองค์ประกอบยาวกว่าหนึ่งไบต์ (ค่อนข้างทุกอย่างอื่นนอกเหนือจากอาร์เรย์อาร์เรย์) Buffer.BlockCopy () ทำงานร่วมกับปริมาณของไบต์ไม่ใช่จำนวนขององค์ประกอบอาร์เรย์ เหตุผลที่สามารถใช้งานได้ง่ายกับอาร์เรย์ไบต์คือทุกองค์ประกอบของอาร์เรย์เป็นไบต์เดียวดังนั้นความยาวทางกายภาพของอาร์เรย์จึงเท่ากับจำนวนองค์ประกอบ ในการเปลี่ยนวิธี byte [] ของ John เป็นวิธีการทั่วไปคุณจะต้องทำการชดเชยและความยาวทั้งหมดด้วยความยาวไบต์ขององค์ประกอบอาร์เรย์เดียวมิฉะนั้นคุณจะไม่คัดลอกข้อมูลทั้งหมด
Daniel Scott

2
โดยปกติแล้วจะทำให้งานนี้คุณคำนวณขนาดขององค์ประกอบเดียวโดยใช้sizeof(...)และคูณด้วยจำนวนองค์ประกอบที่คุณต้องการคัดลอก แต่ขนาดขององค์ประกอบไม่สามารถใช้กับประเภททั่วไปได้ เป็นไปได้ - สำหรับบางประเภท - ที่จะใช้Marshal.SizeOf(typeof(T))แต่คุณจะได้รับข้อผิดพลาดรันไทม์ที่มีบางประเภท (เช่นสตริง) คนที่มีความรู้อย่างละเอียดมากขึ้นเกี่ยวกับการทำงานภายในของประเภท CLR จะสามารถระบุกับดักที่เป็นไปได้ทั้งหมดที่นี่ พอจะกล่าวได้ว่าการเขียนวิธีเรียงต่อกันแบบทั่วไป [ใช้ BlockCopy] นั้นไม่สำคัญ
Daniel Scott

2
และในที่สุด - คุณสามารถเขียนวิธีการเรียงลำดับอาเรย์ทั่วไปแบบนี้ในลักษณะที่แสดงไว้ด้านบน (ด้วยประสิทธิภาพที่ลดลงเล็กน้อย) โดยใช้ Array.Copy แทน เพียงแทนที่การเรียก Buffer.BlockCopy ทั้งหมดด้วยการโทร Array.Copy
Daniel Scott

0
    /// <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();

ขอบคุณสำหรับการสนับสนุน เนื่องจากมีคำตอบที่ได้รับการจัดอันดับสูงจำนวนหนึ่งจากเมื่อสิบกว่าปีที่แล้วจึงมีประโยชน์ที่จะให้คำอธิบายเกี่ยวกับสิ่งที่ทำให้แนวทางของคุณแตกต่าง ทำไมบางคนควรใช้สิ่งนี้แทนเช่นคำตอบที่ยอมรับได้?
Jeremy Caney

ฉันชอบใช้วิธีการเพิ่มเติมเนื่องจากมีรหัสที่ชัดเจนที่จะเข้าใจ รหัสนี้เลือกสองอาร์เรย์พร้อมดัชนีเริ่มต้นและการนับและการต่อเชื่อม ด้วยวิธีนี้ขยาย ดังนั้นนี่คือสำหรับทุกประเภทอาเรย์พร้อมสำหรับทุกครั้ง
เมห์เม็ตÜNLÜ

นั่นทำให้ฉันรู้สึกดี! คุณคิดที่จะแก้ไขคำถามเพื่อรวมข้อมูลนั้นหรือไม่? ฉันคิดว่ามันจะมีค่าสำหรับผู้อ่านในอนาคตที่จะมีความตรงไปตรงมาดังนั้นพวกเขาสามารถแยกแยะวิธีการของคุณจากคำตอบที่มีอยู่ได้อย่างรวดเร็ว ขอบคุณ!
Jeremy Caney

-1

ทั้งหมดที่คุณต้องผ่านรายการ Byte Arrays และฟังก์ชั่นนี้จะคืน Array of Bytes ให้คุณ นี่เป็นทางออกที่ดีที่สุดที่ฉันคิดว่า :)

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

-5

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

5
คำถามนั้นถามหาทางออกที่มีประสิทธิภาพที่สุดโดยเฉพาะ นับไม่ได้ถึงว่าอาเรย์จะไม่มีประสิทธิภาพมากนักเนื่องจากมันไม่รู้ขนาดของอาเรย์สุดท้ายที่จะเริ่มต้นด้วย - ในขณะที่เทคนิคการรีดด้วยมือสามารถทำได้
Jon Skeet
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.