Zusammenführen von zwei Arrays in .NET

225

Gibt es in .NET 2.0 eine integrierte Funktion, die zwei Arrays verwendet und zu einem Array zusammenführt?

Die Arrays sind beide vom gleichen Typ. Ich erhalte diese Arrays von einer weit verbreiteten Funktion in meiner Codebasis und kann die Funktion nicht ändern, um die Daten in einem anderen Format zurückzugeben.

Ich möchte vermeiden, meine eigene Funktion zu schreiben, um dies zu erreichen, wenn dies möglich ist.

kbrinley
quelle

Antworten:

118

Wenn Sie eines der Arrays bearbeiten können, können Sie die Größe ändern, bevor Sie die Kopie ausführen:

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

Andernfalls können Sie ein neues Array erstellen

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

Weitere Informationen zu verfügbaren Array-Methoden in MSDN .

Blair Conrad
quelle
1
Was ist mit .NET 4.0, Neuigkeiten?
Shimmy Weitzhandler
4
Beachten Sie, dass Array.Resizedie Größe des Arrays nicht geändert wird, sondern kopiert wird. Aus diesem Grund ist der erste Parameter by-ref (was bedeutet, dass Ihr erster Code wahrscheinlich nicht kompiliert wird).
CodesInChaos
2
Ich würde nur Ihren ersten Code rauswerfen. Es bietet keinen Vorteil und ist IMO schwerer zu lesen.
CodesInChaos
3
Bitte beachten Sie, dass die Reihenfolge der Parameter im zweiten Codebeispiel für Array.Copy falsch ist. Verwenden Sie Array.Copy (array1, newArray, 0); stattdessen.
Marco Birchler
Sie können auch .. List <Byte> finalArray = new List <Byte> (); finalArray.AddRange (array1); finalArray.AddRange (array2); ==> finalArray.toArray ();
Cédric Boivin
448

In C # 3.0 können Sie die Concat- Methode von LINQ verwenden, um dies einfach zu erreichen:

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

In C # 2.0 haben Sie keinen so direkten Weg, aber Array.Copy ist wahrscheinlich die beste Lösung:

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

Dies könnte leicht verwendet werden, um Ihre eigene Version von zu implementieren Concat.

OwenP
quelle
1
Ich mag diese LINQ-Implementierung. Ich muss wirklich den Sprung machen und bald in LINQ
einsteigen
1
Das Beste an der LINQ-Implementierung ist, dass sie nicht nur präzise ist, sondern auch genauso effizient wie die 2.0-Version, da sie gegen IEnumerable funktioniert.
Brad Wilson
Diese Antwort schließt diesen Weg ein und gibt auch einige Benchmarking-Ergebnisse: stackoverflow.com/questions/415291/…
Demir
Dies ist wahrscheinlich der einfachste Weg, aber dies wird für große Arrays nicht effizient sein, da Concat mit foreach-Schleifen + Ausbeute implementiert wird (siehe Referenzquelle). Eine Lösung mit BlockCopy wird schneller sein.
Tigrou
1
Nur ein kleiner Hinweis: Wenn Sie nur das kombinierte Ergebnis durchlaufen möchten, müssen Sie es nicht in ein Array konvertieren. Diese letzte Operation führt eine Array-Kopie durch. Dies ist nicht erforderlich, wenn Sie eine IEnumerable <int> durchlaufen. Natürlich könnte es gute Gründe geben, ein Array zu haben.
Jonas
82

Verwenden Sie LINQ :

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

Beachten Sie, dass dadurch Duplikate entfernt werden. Wenn Sie Duplikate behalten möchten, verwenden Sie Concat.

Simon B.
quelle
132
VORSICHT: Union entfernt Duplikate.
Yogee
1
@Yogee, leicht zu merken, wie es in SQL ist und auch die Nomenklatur mit der Mengenlehre verbunden ist.
Zbigniew Wiadro
8
Da Duplikate entfernt werden, kann dies niemals eine richtige Antwort sein.
Roni Tovi
1
Ich sehe, dass Simon bereits das Thema Union und den von ihm vorgeschlagenen alternativen Ansatz erwähnt hat. Darüber müssen Sie nicht weiter diskutieren, da Simon weiß, was er antwortet.
Sudhakar Chavali
40

Wenn Sie keine Duplikate entfernen möchten, versuchen Sie dies

Verwenden Sie LINQ:

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

Stellen Sie sich zunächst die Frage "Soll ich hier wirklich ein Array verwenden"?

Wenn Sie nicht etwas erstellen, bei dem Geschwindigkeit von größter Bedeutung ist, ist eine typisierte Liste List<int>wahrscheinlich der richtige Weg. Das einzige Mal, dass ich Arrays verwende, sind Byte-Arrays, wenn Dinge über das Netzwerk gesendet werden. Davon abgesehen berühre ich sie nie.

CodesInChaos
quelle
Big +1 hier. Beachten Sie, dass die beste Vorgehensweise darin besteht, das Offenlegen List<T>in öffentlichen APIs zu vermeiden : blogs.msdn.com/b/kcwalina/archive/2005/09/26/474010.aspx
TrueWill
10

Einfacher wäre nur die Verwendung von LINQ :

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

Konvertieren Sie zuerst die Arrays in Listen und führen Sie sie zusammen ... Danach konvertieren Sie die Liste einfach zurück in ein Array :)

Angelo Ortega
quelle
Sie werden nicht direkt Array verwendet. Du hast List benutzt!
Behzad Ebrahimi
7

Ich denke, Sie können Array.Copy dafür verwenden. Es werden ein Quellindex und ein Zielindex benötigt, damit Sie das eine Array an das andere anhängen können. Wenn Sie komplexer werden müssen, als nur eines an das andere anzuhängen, ist dies möglicherweise nicht das richtige Werkzeug für Sie.

GEOCHET
quelle
5

Angenommen, das Zielarray verfügt über genügend Speicherplatz, Array.Copy()funktioniert. Sie können auch versuchen, a List<T>und seine .AddRange()Methode zu verwenden.

Joel Coehoorn
quelle
4

Persönlich bevorzuge ich meine eigenen Spracherweiterungen, die ich für Rapid Prototyping nach Belieben hinzufüge oder entferne.

Das Folgende ist ein Beispiel für Zeichenfolgen.

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

Es ist viel schneller als LINQ und Concat. Noch schneller wird ein benutzerdefinierter IEnumerableType-Wrapper verwendet, der Referenzen / Zeiger von übergebenen Arrays speichert und das Durchlaufen der gesamten Sammlung ermöglicht, als wäre es ein normales Array. (Nützlich in HPC, Grafikverarbeitung, Grafik-Rendering ...)

Dein Code:

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

Den gesamten Code und eine generische Version finden Sie unter: https://gist.github.com/lsauer/7919764

Hinweis: Dies gibt ein nicht erweitertes IEnumerable-Objekt zurück. Das Zurückgeben eines erweiterten Objekts ist etwas langsamer.

Ich habe solche Erweiterungen seit 2002 zusammengestellt, wobei viele Credits an hilfreiche Leute in CodeProject und 'Stackoverflow' gingen. Ich werde diese in Kürze veröffentlichen und den Link hier einfügen.

Lorenz Lo Sauer
quelle
4

Jeder hat bereits zu Wort gekommen, aber ich denke, dies ist lesbarer als der Ansatz "Als Erweiterungsmethode verwenden":

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

Es kann jedoch nur verwendet werden, wenn 2 Arrays zusammengeführt werden.

John Reilly
quelle
4

Das habe ich mir ausgedacht. Funktioniert für eine variable Anzahl von Arrays.

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
quelle
3

Nur um es als Option notieren zu lassen: Wenn die Arrays, mit denen Sie arbeiten, vom primitiven Typ sind - Boolescher Wert (Bool), Char, SByte, Byte, Int16 (kurz), UInt16, Int32 (int), UInt32, Int64 (lang) ), UInt64, IntPtr, UIntPtr, Single oder Double - dann könnten (oder sollten?) Sie versuchen, Buffer.BlockCopy zu verwenden . Laut der MSDN-Seite für die Pufferklasse :

Diese Klasse bietet eine bessere Leistung für die Bearbeitung primitiver Typen als ähnliche Methoden in der System.Array- Klasse.

Mit dem C # 2.0-Beispiel aus der Antwort von @ OwenP als Ausgangspunkt würde es wie folgt funktionieren:

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

Es gibt kaum einen Unterschied in der Syntax zwischen Buffer.BlockCopyund der von Array.Copy@OwenP verwendeten, aber diese sollte schneller sein (wenn auch nur geringfügig).

Solomon Rutzky
quelle
2

Falls jemand anderes nach Möglichkeiten sucht, zwei Bildbyte-Arrays zusammenzuführen:

        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
quelle
1

Hier ist ein einfaches Beispiel für die Verwendung von Array.CopyTo. Ich denke, dass es Ihre Frage beantwortet und ein Beispiel für die Verwendung von CopyTo gibt. Ich bin immer verwirrt, wenn ich diese Funktion verwenden muss, da die Hilfe etwas unklar ist. Der Index ist die Position im Zielarray, an der das Einfügen erfolgt.

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

Einfacher geht es wohl nicht.

pasx
quelle
1

Ich brauchte eine Lösung, um eine unbekannte Anzahl von Arrays zu kombinieren.

Überrascht bot niemand sonst eine Lösung SelectManymit params.

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

Wenn Sie keine eindeutigen Elemente möchten, entfernen Sie einfach unterschiedliche Elemente.

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

Hinweis: Es gibt definitiv keine Garantie für die Bestellung bei Verwendung von eindeutigen.

Simon_Weaver
quelle
0

Ich gehe davon aus, dass Sie im Gegensatz zu den integrierten .NET-Arrays Ihre eigenen Array-Typen verwenden:

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

Eine andere Möglichkeit wäre die Verwendung der integrierten ArrayList-Klasse.

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

Beide Beispiele sind C #.

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

Mit dem obigen Code können zwei Arrays einfach zusammengeführt werden.

vikasse
quelle
0

Erstellt und Erweiterungsmethode für 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;
    }
}
Lord Darth Vader
quelle
0

Wenn Sie die Quell-Arrays in einem Array selbst haben, können Sie SelectMany verwenden :

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

gibt

1
2
3
4
5
6

Wahrscheinlich ist dies nicht die schnellste Methode, könnte aber je nach Anwendungsfall passen.

schoetbi
quelle
-1

Dieser Code funktioniert in allen Fällen:

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.
quelle
Könnten Sie bitte eine weitere Beschreibung der von Ihnen angebotenen Lösung hinzufügen?
Abarisone
1
Während dieses Code-Snippet die Frage lösen kann, hilft das Hinzufügen einer Erklärung wirklich, die Qualität Ihres Beitrags zu verbessern. Denken Sie daran, dass Sie die Frage für Leser in Zukunft beantworten und diese Personen möglicherweise die Gründe für Ihren Codevorschlag nicht kennen.
gunr2171
Dies scheint eine sortierte Zusammenführung zu sein, die zwar für sich genommen nützlich ist (hauptsächlich als Teil einer rekursiven MergeSort-Strategie), aber möglicherweise mehr ist, als das OP verlangt hat.
Darrel Hoffman
Während diese Lösung funktioniert, sind viele Techniken seit Einführung von C # und VB.Net möglicherweise nicht verfügbar.
Sudhakar Chavali
-2

Versuche dies:

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