İki diziyi .NET'te birleştirme


225

.NET 2.0'da iki diziyi alıp bunları tek bir dizide birleştirecek yerleşik bir işlev var mı?

Dizilerin her ikisi de aynı türdendir. Bu diziler benim kod tabanı içinde yaygın olarak kullanılan bir işlev alıyorum ve farklı bir biçimde veri döndürmek için işlevi değiştiremiyorum.

Mümkünse bunu gerçekleştirmek için kendi işlevimi yazmaktan kaçınmak istiyorum.

Yanıtlar:


118

Dizilerden birini işleyebiliyorsanız, kopyayı gerçekleştirmeden önce yeniden boyutlandırabilirsiniz:

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

Aksi takdirde, yeni bir dizi oluşturabilirsiniz

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

MSDN'deki kullanılabilir Dizi yöntemleri hakkında daha fazla bilgi .


1
.NET 4.0'a ne dersiniz?
Shimmy Weitzhandler

4
Not Array.Resizeaslında dizi, bu kopyalar boyutunu değiştirmez. Bu yüzden ilk parametre by-ref'dir (bu, ilk kodunuzun muhtemelen derlenmeyeceği anlamına gelir).
CodesInChaos

2
Sadece ilk kod parçanýzý atarým. Bir avantaj sağlamaz ve IMO'yu okumak daha zordur.
CodesInChaos

3
Array.Copy için ikinci kod örneğindeki parametrelerin sırasının yanlış olduğunu lütfen unutmayın. Array.Copy (dizi1, newArray, 0) kullanın; yerine.
marco birchler

Şunları da yapabilirsiniz .. List <byte> finalArray = new List <byte> (); finalArray.AddRange (array1); finalArray.AddRange (array2); ==> finalArray.toArray ();
Cédric Boivin

448

C # 3.0'da bunu kolayca gerçekleştirmek için LINQ'nun Concat yöntemini kullanabilirsiniz:

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

C # 2.0'da böyle doğrudan bir yolunuz yok, ancak Array.Copy muhtemelen en iyi çözümdür:

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

Bu, kendi sürümünüzü uygulamak için kolayca kullanılabilir Concat.


1
Bu LINQ uygulamasını seviyorum. Gerçekten atlamak ve yakında LINQ almak gerekir ...
GEOCHET

1
Zengin, LINQ uygulamasının en iyi yanı, sadece kısa değil, aynı zamanda 2.0 sürümü kadar da verimli olmasıdır, çünkü IEnumerable'a karşı çalışır.
Brad Wilson

Bu yanıt bu yolu içerir ve bazı kıyaslama sonuçları da verir: stackoverflow.com/questions/415291/…
Demir

Muhtemelen en kolay yol budur, ancak Concat foreach döngüler + verim kullanılarak uygulandığından, büyük diziler için verimli olmayacaktır (referans kaynağına bakın). BlockCopy ile bir çözüm daha hızlı olacaktır.
tigrou

1
Sadece küçük bir kafa yukarı: sadece birleşik sonuç boyunca yineleme yapmak istiyorsanız, onu bir diziye dönüştürmeye gerek yoktur. Bu son işlem bir dizi kopyası yapar. IEnumerable <int> üzerinden yinelerseniz bunu yapmak zorunda kalmayacaksınız. Tabii ki, bir dizi olması için iyi nedenler olabilir.
Jonas

82

LINQ kullanın :

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

Unutmayın, bu kopyaları kaldıracaktır. Kopyaları saklamak istiyorsanız, Concat kullanın.


132
DİKKAT: Birlik kopyaları kaldıracaktır.
Yogee

1
@Yogee, SQL'de olduğu gibi hatırlanması kolay ve aynı zamanda isimlendirme kümeleri teorisi ile bağlantılıdır.
Zbigniew Wiadro

8
yinelemeleri kaldıracağından, asla uygun bir yanıt olamaz.
Roni Tovi

1
Simon'ın Birlik meselesinden ve önerdiği alternatif yaklaşımdan bahsettiğini görüyorum. Simon'un neye cevap verdiğini bildiği için bunun hakkında daha fazla tartışmaya gerek yok.
Sudhakar Chavali

41

Kopyaları kaldırmak istemiyorsanız, bunu deneyin

LINQ kullanın:

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

11

Öncelikle, kendinize "Burada gerçekten bir Array kullanmalı mıyım?" Sorusunu sorduğunuzdan emin olun.

Hızın çok önemli olduğu bir şey inşa etmedikçe, yazılı bir Liste, List<int>muhtemelen gitmenin yolu. Şimdiye kadar dizileri kullandığım tek zaman, ağ üzerinden bir şeyler gönderirken bayt dizileri içindir. Bunun dışında onlara asla dokunmuyorum.


Burada büyük +1. En iyi uygulamanın List<T>herkese açık API'larda gösterilmekten kaçınmak olduğunu unutmayın : blogs.msdn.com/b/kcwalina/archive/2005/09/26/474010.aspx
TrueWill

10

Daha kolay olan sadece LINQ kullanmak olacaktır :

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

Önce dizileri listelere dönüştürün ve birleştirin ... Bundan sonra listeyi tekrar diziye dönüştürün :)


Doğrudan dizi kullanılmaz. Listeyi kullandınız!
Behzad Ebrahimi

7

Bunun için Array.Copy kullanabilirsiniz . Bir kaynak dizini ve hedef dizini alır, böylece bir diziyi diğerine ekleyebilmeniz gerekir. Birini diğerine eklemekten daha karmaşık olmanız gerekiyorsa, bu sizin için doğru araç olmayabilir.



4

Şahsen, hızlı prototipleme için eklediğim veya kaldırdığım kendi Dil Uzantılarımı tercih ediyorum.

Aşağıda dizelere bir örnek verilmiştir.

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

LINQ ve Concat'tan çok daha hızlıdır. Daha hızlı bir şekilde IEnumerable, geçirilen dizilerin referanslarını / işaretleyicilerini saklayan ve tüm koleksiyon üzerinde normal bir dizi gibi döngü oluşturmayı sağlayan özel bir Type-wrapper kullanıyor . (HPC, Grafik İşleme, Grafik oluşturma ...)

Senin kodun:

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

Kodun tamamı ve genel sürüm için bkz. Https://gist.github.com/lsauer/7919764

Not: Bu genişletilmemiş bir IEnumerable nesnesi döndürür. Genişletilmiş bir nesneyi döndürmek biraz daha yavaştır.

Bu uzantıları 2002'den beri derledim, CodeProject ve 'Stackoverflow' konusunda çok sayıda krediye yardımcı oluyorum. Bunları kısa süre içinde yayınlayacağım ve bağlantıyı buraya koyacağım.


4

Herkes zaten söz vardı ama bu "Uzantı yöntemi olarak kullanmak" yaklaşım daha okunabilir düşünüyorum:

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

Ancak sadece 2 diziyi bir araya getirirken kullanılabilir.


4

Ben de bunu buldum. Değişken sayıda dizi için çalışır.

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 }

3

Sadece bir seçenek olarak belirtmek için: birlikte çalıştığınız diziler ilkel türdeyse - Boolean (bool), Char, SByte, Byte, Int16 (kısa), UInt16, Int32 (int), UInt32, Int64 (uzun ), UInt64, IntPtr, UIntPtr, Single veya Double - o zaman Buffer.BlockCopy kullanmayı deneyebilirsiniz (veya yapmalısınız?) . Buffer sınıfının MSDN sayfasına göre :

Bu sınıf, ilkel türlerin işlenmesi için System.Array sınıfındaki benzer yöntemlere göre daha iyi performans sağlar .

OwenP en @ C # 2.0 örneği kullanarak cevap başlangıç noktası olarak, bu aşağıdaki gibi çalışır:

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

Orada arasında sözdiziminde herhangi bir fark zorlukla olduğunu Buffer.BlockCopyve Array.Copy@OwenP kullandığı, ancak bu (hatta sadece biraz varsa) daha hızlı olmalıdır.


2

Başka birinin iki görüntü bayt dizisini nasıl birleştireceğini araştırması durumunda:

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

1

İşte Array.CopyTo kullanarak basit bir örnek. Sorunuzu cevaplar ve CopyTo kullanımı bir örnek verir düşünüyorum - Yardım biraz belirsiz olduğu için bu işlevi kullanmanız gerektiğinde her zaman şaşkınım - dizin ekleme hedef dizisinde konumdur.

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

Sanırım çok daha basit olamazsın.


1

Bilinmeyen sayıda diziyi birleştirmek için bir çözüme ihtiyacım vardı.

Kimse SelectManyile kullanarak bir çözüm sağlama şaşırttı params.

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

Farklı öğeler istemiyorsanız, yalnızca farklı öğeleri kaldırın.

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

Not: Farklı kullanırken kesinlikle sipariş garantisi yoktur.


0

Yerleşik .NET dizilerinin aksine kendi dizi türlerinizi kullandığınızı varsayıyorum:

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

Bunu yapmanın başka bir yolu da yerleşik ArrayList sınıfını kullanmak olacaktır.

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

Her iki örnek de C #.


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

Yukarıdaki kodu kullanarak iki Dizi kolayca birleştirilebilir.


0

Boş işlemek için oluşturulan ve genişletme yöntemi

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

0

Bir dizinin kendisinde kaynak diziler varsa SelectMany'yi kullanabilirsiniz :

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

verir

1
2
3
4
5
6

Muhtemelen bu en hızlı yöntem değildir ancak usecase'e bağlı olarak uygun olabilir.


-1

Bu kod tüm durumlar için çalışacaktır:

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

Lütfen sağladığınız çözüm hakkında daha fazla açıklama ekler misiniz?
abarisone

1
Bu kod snippet'i soruyu çözebilir, ancak bir açıklama dahil olmak , yayınınızın kalitesini artırmaya yardımcı olur. Gelecekte okuyucular için soruyu cevapladığınızı ve bu kişilerin kod önerinizin nedenlerini bilmeyebileceğini unutmayın.
gunr2171

Bu, kendi başına yararlı olsa da (esas olarak bir MergeSort özyinelemeli stratejinin bir parçası olarak), OP'nin istediklerinden daha fazla olabilen sıralı bir birleştirme gibi görünüyor.
Darrel Hoffman

Bu çözüm çalışırken, C # ve VB.Net tanıtıldığından beri birçok tekniğe sahip olmak insanlar bu çözümleri tercih etmeyebilir.
Sudhakar Chavali

-2

Bunu dene:

ArrayLIst al = new ArrayList();
al.AddRange(array_1);
al.AddRange(array_2);
al.AddRange(array_3);
array_4 = al.ToArray();
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.