Menggabungkan dua array di .NET

225

Apakah ada fungsi built in. NET 2.0 yang akan mengambil dua array dan menggabungkannya menjadi satu array?

Array keduanya memiliki tipe yang sama. Saya mendapatkan array ini dari fungsi yang banyak digunakan dalam basis kode saya dan tidak dapat memodifikasi fungsi untuk mengembalikan data dalam format yang berbeda.

Saya ingin menghindari menulis fungsi saya sendiri untuk menyelesaikan ini jika memungkinkan.

kbrinley
sumber

Jawaban:

118

Jika Anda dapat memanipulasi salah satu array, Anda dapat mengubah ukurannya sebelum melakukan salinan:

T[] array1 = getOneArray();
T[] array2 = getAnotherArray();
int array1OriginalLength = array1.Length;
Array.Resize<T>(ref array1, array1OriginalLength + array2.Length);
Array.Copy(array2, 0, array1, array1OriginalLength, array2.Length);

Jika tidak, Anda dapat membuat array baru

T[] array1 = getOneArray();
T[] array2 = getAnotherArray();
T[] newArray = new T[array1.Length + array2.Length];
Array.Copy(array1, newArray, array1.Length);
Array.Copy(array2, 0, newArray, array1.Length, array2.Length);

Lebih lanjut tentang metode Array yang tersedia di MSDN .

Blair Conrad
sumber
1
Bagaimana dengan .NET 4.0, ada berita?
Shimmy Weitzhandler
4
Catatan yang Array.Resizesebenarnya tidak mengubah ukuran array, itu menyalinnya. Itu sebabnya parameter pertama adalah by-ref (yang berarti kode pertama Anda mungkin tidak akan dikompilasi).
CodesInChaos
2
Saya hanya akan membuang potongan kode pertama Anda. Itu tidak menawarkan keuntungan, dan lebih sulit untuk membaca IMO.
CodesInChaos
3
Harap dicatat bahwa urutan parameter dalam contoh kode kedua untuk Array.Copy salah. Gunakan Array.Copy (array1, newArray, 0); sebagai gantinya.
marco birchler
Anda juga dapat melakukannya .. Daftar <byte> finalArray = Daftar baru <byte> (); finalArray.AddRange (array1); finalArray.AddRange (array2); ==> finalArray.toArray ();
Cédric Boivin
448

Di C # 3.0 Anda dapat menggunakan metode Concat LINQ untuk melakukannya dengan mudah:

int[] front = { 1, 2, 3, 4 };
int[] back = { 5, 6, 7, 8 };
int[] combined = front.Concat(back).ToArray();

Di C # 2.0 Anda tidak memiliki cara langsung, tetapi Array.Copy mungkin solusi terbaik:

int[] front = { 1, 2, 3, 4 };
int[] back = { 5, 6, 7, 8 };

int[] combined = new int[front.Length + back.Length];
Array.Copy(front, combined, front.Length);
Array.Copy(back, 0, combined, front.Length, back.Length);

Ini dapat dengan mudah digunakan untuk mengimplementasikan versi Anda sendiri Concat.

OwenP
sumber
1
Saya suka itu implementasi LINQ. Saya benar-benar harus melakukan lompatan dan masuk ke LINQ segera ...
GEOCHET
1
Kaya, bagian terbaik tentang implementasi LINQ tidak hanya singkat, tetapi juga seefisien versi 2.0, karena bekerja melawan IEnumerable.
Brad Wilson
Jawaban ini mencakup cara ini dan juga memberikan beberapa hasil pembandingan: stackoverflow.com/questions/415291/…
Demir
Ini mungkin cara termudah tetapi ini tidak akan efisien untuk array besar, karena Concat diimplementasikan menggunakan foreach loop + hasil (lihat sumber referensi). Solusi dengan BlockCopy akan lebih cepat.
tigrou
1
Hanya kepala kecil ke atas: jika Anda hanya ingin mengulang melalui hasil gabungan, tidak perlu mengubahnya menjadi array. Operasi terakhir itu melakukan copy array. Tidak perlu melakukan itu jika Anda mengulang melalui <n> IEnumerable. Tentu saja, mungkin ada alasan bagus untuk menjadikannya array.
Jonas
82

Gunakan LINQ :

var arr1 = new[] { 1, 2, 3, 4, 5 };
var arr2 = new[] { 6, 7, 8, 9, 0 };
var arr = arr1.Union(arr2).ToArray();

Perlu diingat, ini akan menghapus duplikat. Jika Anda ingin menyimpan duplikat, gunakan Concat.

Simon B.
sumber
132
PERHATIAN: Serikat pekerja akan menghapus duplikat.
Yogee
1
@Yogee, mudah diingat seperti di SQL dan nomenklaturnya terhubung dengan teori himpunan.
Zbigniew Wiadro
8
karena itu akan menghapus duplikat, itu tidak akan pernah menjadi jawaban yang tepat.
Roni Tovi
1
Saya melihat Simon sudah menyebutkan masalah Union dan pendekatan alternatif yang disarankannya. Tidak perlu membahas lebih lanjut tentang itu karena Simon tahu apa yang dia jawab.
Sudhakar Chavali
41

Jika Anda tidak ingin menghapus duplikat, coba ini

Gunakan LINQ:

var arr1 = new[] { 1, 2, 3, 4, 5 };
var arr2 = new[] { 6, 7, 8, 9, 0 };
var arr = arr1.Concat(arr2).ToArray();
Smith
sumber
11

Pertama, pastikan Anda bertanya pada diri sendiri pertanyaan "Haruskah saya benar-benar menggunakan Array di sini"?

Kecuali jika Anda sedang membangun sesuatu di mana kecepatan adalah yang paling penting, Daftar yang diketik, seperti List<int>mungkin adalah cara untuk pergi. Satu-satunya waktu saya pernah menggunakan array adalah untuk byte array ketika mengirim barang melalui jaringan. Selain itu, saya tidak pernah menyentuh mereka.

CodesInChaos
sumber
+1 besar di sini. Perhatikan bahwa praktik terbaik adalah untuk menghindari mengekspos List<T>di API publik: blogs.msdn.com/b/kcwalina/archive/2005/09/26/474010.aspx
TrueWill
10

Lebih mudah hanya menggunakan LINQ :

var array = new string[] { "test" }.ToList();
var array1 = new string[] { "test" }.ToList();
array.AddRange(array1);
var result = array.ToArray();

Pertama-tama konversikan array ke daftar dan gabungkan mereka ... Setelah itu konversikan daftar kembali menjadi sebuah array :)

Angelo Ortega
sumber
Anda tidak menggunakan array secara langsung. Anda menggunakan Daftar!
Behzad Ebrahimi
7

Saya pikir Anda dapat menggunakan Array . Salin untuk ini. Dibutuhkan indeks sumber dan indeks tujuan sehingga Anda harus dapat menambahkan satu array ke array lainnya. Jika Anda perlu lebih rumit daripada hanya menambahkan satu ke yang lain, ini mungkin bukan alat yang tepat untuk Anda.

GEOCHET
sumber
5

Dengan asumsi array tujuan memiliki cukup ruang, Array.Copy()akan berfungsi. Anda mungkin juga mencoba menggunakan a List<T>dan .AddRange()metodenya.

Joel Coehoorn
sumber
4

Secara pribadi, saya lebih suka Ekstensi Bahasa saya sendiri, yang saya tambahkan atau hapus sesuka hati untuk pembuatan prototipe cepat.

Berikut ini adalah contoh untuk string.

//resides in IEnumerableStringExtensions.cs
public static class IEnumerableStringExtensions
{
   public static IEnumerable<string> Append(this string[] arrayInitial, string[] arrayToAppend)
   {
       string[] ret = new string[arrayInitial.Length + arrayToAppend.Length];
       arrayInitial.CopyTo(ret, 0);
       arrayToAppend.CopyTo(ret, arrayInitial.Length);

       return ret;
   }
}

Ini jauh lebih cepat daripada LINQ dan Concat. Lebih cepat lagi, menggunakan custom IEnumerableType-wrapper yang menyimpan referensi / pointer dari array yang dilewati dan memungkinkan perulangan seluruh koleksi seolah-olah itu adalah array normal. (Berguna dalam HPC, Pemrosesan Grafik, Pembuatan grafik ...)

Kode Anda:

var someStringArray = new[]{"a", "b", "c"};
var someStringArray2 = new[]{"d", "e", "f"};
someStringArray.Append(someStringArray2 ); //contains a,b,c,d,e,f

Untuk keseluruhan kode dan versi generik, lihat: https://gist.github.com/lsauer/7919764

Catatan: Ini mengembalikan objek IEnumerable tanpa ekstensi. Untuk mengembalikan objek yang diperluas sedikit lebih lambat.

Saya mengkompilasi ekstensi tersebut sejak 2002, dengan banyak kredit akan membantu orang-orang di CodeProject dan 'Stackoverflow'. Saya akan segera merilis ini dan meletakkan tautannya di sini.

Lorenz Lo Sauer
sumber
4

Semua orang sudah memiliki pendapat mereka tetapi saya pikir ini lebih mudah dibaca daripada pendekatan "gunakan sebagai metode Extension":

var arr1 = new[] { 1, 2, 3, 4, 5 };
var arr2 = new[] { 6, 7, 8, 9, 0 };
var arr = Queryable.Concat(arr1, arr2).ToArray();

Namun itu hanya dapat digunakan saat menyatukan 2 array.

John Reilly
sumber
4

Inilah yang saya pikirkan. Berfungsi untuk sejumlah array.

public static T[] ConcatArrays<T>(params T[][] args)
    {
        if (args == null)
            throw new ArgumentNullException();

        var offset = 0;
        var newLength = args.Sum(arr => arr.Length); 
        var newArray = new T[newLength];

        foreach (var arr in args)
        {
            Buffer.BlockCopy(arr, 0, newArray, offset, arr.Length);
            offset += arr.Length;
        }

        return newArray;
    }

...

var header = new byte[] { 0, 1, 2};
var data = new byte[] { 3, 4, 5, 6 };
var checksum = new byte[] {7, 0};
var newArray = ConcatArrays(header, data, checksum);
//output byte[9] { 0, 1, 2, 3, 4, 5, 6, 7, 0 }
cj.burrow
sumber
3

Untuk mencatatnya sebagai opsi: jika array yang Anda gunakan memiliki tipe primitif - Boolean (bool), Char, SByte, Byte, Int16 (pendek), UInt16, Int32 (int), UInt32, Int64 (panjang ), UInt64, IntPtr, UIntPtr, Single, atau Double - maka Anda bisa (atau harus?) Mencoba menggunakan Buffer.BlockCopy . Menurut halaman MSDN untuk kelas Buffer :

Kelas ini memberikan kinerja yang lebih baik untuk memanipulasi tipe primitif daripada metode serupa di kelas System.Array .

Menggunakan contoh C # 2.0 dari jawaban @ OwenP sebagai titik awal, ini akan berfungsi sebagai berikut:

int[] front = { 1, 2, 3, 4 };
int[] back = { 5, 6, 7, 8 };

int[] combined = new int[front.Length + back.Length];
Buffer.BlockCopy(front, 0, combined, 0, front.Length);
Buffer.BlockCopy(back, 0, combined, front.Length, back.Length);

Hampir tidak ada perbedaan dalam sintaksis antara Buffer.BlockCopydan Array.Copyyang @OwenP gunakan, tetapi ini harus lebih cepat (bahkan jika hanya sedikit).

Solomon Rutzky
sumber
2

Jika ada orang lain yang mencari cara menggabungkan dua array byte gambar:

        private void LoadImage()
        {
            string src = string.empty;
            byte[] mergedImageData = new byte[0];

            mergedImageData = MergeTwoImageByteArrays(watermarkByteArray, backgroundImageByteArray);
            src = "data:image/png;base64," + Convert.ToBase64String(mergedImageData);
            MyImage.ImageUrl = src;
        }

        private byte[] MergeTwoImageByteArrays(byte[] imageBytes, byte[] imageBaseBytes)
        {
            byte[] mergedImageData = new byte[0];
            using (var msBase = new MemoryStream(imageBaseBytes))
            {
                System.Drawing.Image imgBase = System.Drawing.Image.FromStream(msBase);
                Graphics gBase = Graphics.FromImage(imgBase);
                using (var msInfo = new MemoryStream(imageBytes))
                {
                    System.Drawing.Image imgInfo = System.Drawing.Image.FromStream(msInfo);
                    Graphics gInfo = Graphics.FromImage(imgInfo);
                    gBase.DrawImage(imgInfo, new Point(0, 0));
                    //imgBase.Save(Server.MapPath("_____testImg.png"), ImageFormat.Png);
                    MemoryStream mergedImageStream = new MemoryStream();
                    imgBase.Save(mergedImageStream, ImageFormat.Png);
                    mergedImageData = mergedImageStream.ToArray();
                    mergedImageStream.Close();
                }
            }
            return mergedImageData;
        }
Lukas
sumber
1

Berikut adalah contoh sederhana menggunakan Array.CopyTo. Saya pikir itu menjawab pertanyaan Anda dan memberikan contoh penggunaan CopyTo - Saya selalu bingung ketika saya perlu menggunakan fungsi ini karena bantuannya agak tidak jelas - indeks adalah posisi di array tujuan di mana penyisipan terjadi.

int[] xSrc1 = new int[3] { 0, 1, 2 };
int[] xSrc2 = new int[5] { 3, 4, 5, 6 , 7 };

int[] xAll = new int[xSrc1.Length + xSrc2.Length];
xSrc1.CopyTo(xAll, 0);
xSrc2.CopyTo(xAll, xSrc1.Length);

Saya kira Anda tidak bisa membuatnya lebih sederhana.

pasx
sumber
1

Saya membutuhkan solusi untuk menggabungkan jumlah array yang tidak diketahui.

Heran tidak ada lagi yang memberikan solusi menggunakan SelectManydengan params.

 private static T[] Combine<T>(params IEnumerable<T>[] items) =>
                    items.SelectMany(i => i).Distinct().ToArray();

Jika Anda tidak ingin item yang berbeda, hapus saja yang berbeda.

 public string[] Reds = new [] { "Red", "Crimson", "TrafficLightRed" };
 public string[] Greens = new [] { "Green", "LimeGreen" };
 public string[] Blues = new [] { "Blue", "SkyBlue", "Navy" };

 public string[] Colors = Combine(Reds, Greens, Blues);

Catatan: Pasti tidak ada jaminan pemesanan saat menggunakan berbeda.

Simon_Weaver
sumber
0

Saya berasumsi Anda menggunakan tipe array Anda sendiri sebagai lawan dari .NET array:

public string[] merge(input1, input2)
{
    string[] output = new string[input1.length + input2.length];
    for(int i = 0; i < output.length; i++)
    {
        if (i >= input1.length)
            output[i] = input2[i-input1.length];
        else
            output[i] = input1[i];
    }
    return output;
}

Cara lain untuk melakukan ini adalah dengan menggunakan kelas ArrayList bawaan.

public ArrayList merge(input1, input2)
{
    Arraylist output = new ArrayList();
    foreach(string val in input1)
        output.add(val);
    foreach(string val in input2)
        output.add(val);
    return output;
}

Kedua contoh adalah C #.

apandit
sumber
0
int [] SouceArray1 = new int[] {2,1,3};
int [] SourceArray2 = new int[] {4,5,6};
int [] targetArray = new int [SouceArray1.Length + SourceArray2.Length];
SouceArray1.CopyTo(targetArray,0);
SourceArray2.CopyTo(targetArray,SouceArray1.Length) ; 
foreach (int i in targetArray) Console.WriteLine(i + " ");  

Menggunakan kode di atas dua Array dapat dengan mudah digabungkan.

vikasse
sumber
0

Dibuat dan metode ekstensi untuk menangani null

public static class IEnumerableExtenions
{
    public static IEnumerable<T> UnionIfNotNull<T>(this IEnumerable<T> list1, IEnumerable<T> list2)
    {
        if (list1 != null && list2 != null)
            return list1.Union(list2);
        else if (list1 != null)
            return list1;
        else if (list2 != null)
            return list2;
        else return null;
    }
}
Tuan Darth Vader
sumber
0

Jika Anda memiliki array sumber di dalam array itu sendiri, Anda dapat menggunakan SelectMany :

var arrays = new[]{new[]{1, 2, 3}, new[]{4, 5, 6}};
var combined = arrays.SelectMany(a => a).ToArray();
foreach (var v in combined) Console.WriteLine(v);   

memberi

1
2
3
4
5
6

Mungkin ini bukan metode tercepat tetapi mungkin cocok tergantung pada usecase.

schoetbi
sumber
-1

Kode ini akan berfungsi untuk semua kasus:

int[] a1 ={3,4,5,6};
int[] a2 = {4,7,9};
int i = a1.Length-1;
int j = a2.Length-1;
int resultIndex=  i+j+1;
Array.Resize(ref a2, a1.Length +a2.Length);
while(resultIndex >=0)
{
    if(i != 0 && j !=0)
    {
        if(a1[i] > a2[j])
        {
            a2[resultIndex--] = a[i--];
        }
        else
        {
            a2[resultIndex--] = a[j--];
        }
    }
    else if(i>=0 && j<=0)
    { 
        a2[resultIndex--] = a[i--];
    }
    else if(j>=0 && i <=0)
    {
       a2[resultIndex--] = a[j--];
    }
}
Rajkumar M
sumber
Bisakah Anda menambahkan deskripsi lebih lanjut tentang solusi yang Anda berikan?
abarisone
1
Sementara potongan kode ini dapat menyelesaikan pertanyaan, termasuk penjelasan sangat membantu untuk meningkatkan kualitas posting Anda. Ingatlah bahwa Anda menjawab pertanyaan untuk pembaca di masa depan, dan orang-orang itu mungkin tidak tahu alasan untuk saran kode Anda.
gunr2171
Ini tampaknya merupakan penggabungan yang diurutkan, yang walaupun berguna dalam haknya sendiri (terutama sebagai bagian dari strategi rekursif MergeSort), mungkin lebih dari yang diminta OP.
Darrel Hoffman
Sementara solusi ini bekerja, memiliki banyak teknik yang tersedia sejak C # dan VB.Net diperkenalkan, orang mungkin tidak suka solusi tersebut.
Sudhakar Chavali
-2

Coba ini:

ArrayLIst al = new ArrayList();
al.AddRange(array_1);
al.AddRange(array_2);
al.AddRange(array_3);
array_4 = al.ToArray();
namco
sumber