Unione di due array in .NET


225

Esiste una funzione integrata in .NET 2.0 che accetta due array e li unisce in un array?

Gli array sono entrambi dello stesso tipo. Ricevo questi array da una funzione ampiamente usata nella mia base di codice e non riesco a modificare la funzione per restituire i dati in un formato diverso.

Sto cercando di evitare di scrivere la mia funzione per farlo se possibile.

Risposte:


118

Se riesci a manipolare una delle matrici, puoi ridimensionarla prima di eseguire la copia:

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

Altrimenti, puoi creare un nuovo array

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

Ulteriori informazioni sui metodi di array disponibili su MSDN .


1
Che dire di .NET 4.0, qualche novità?
Shimmy Weitzhandler,

4
Si noti che in Array.Resizerealtà non ridimensiona l'array, ma lo copia. Ecco perché il primo parametro è by-ref (il che significa che probabilmente il tuo primo codice non verrà compilato).
Codici A Caos il

2
Vorrei solo buttare via il tuo primo pezzo di codice. Non offre alcun vantaggio ed è più difficile leggere IMO.
Codici A Caos il

3
Si noti che l'ordine dei parametri nel secondo esempio di codice per Array.Copy è errato. Usa Array.Copy (array1, newArray, 0); anziché.
marco birchler,

Puoi anche fare .. List <byte> finalArray = new List <byte> (); finalArray.AddRange (array1); finalArray.AddRange (array2); ==> finalArray.toArray ();
Cédric Boivin,

448

In C # 3.0 è possibile utilizzare il metodo Concat di LINQ per ottenere questo facilmente:

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

In C # 2.0 non hai un modo così diretto, ma Array.Copy è probabilmente la soluzione migliore:

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

Questo potrebbe essere facilmente utilizzato per implementare la tua versione di Concat.


1
Mi piace l'implementazione di LINQ. Ho davvero bisogno di fare il salto ed entrare presto in LINQ ...
GEOCHET,

1
Ricca, la parte migliore dell'implementazione di LINQ non è solo concisa, ma anche efficiente come la versione 2.0, poiché funziona con IEnumerable.
Brad Wilson,

Questa risposta include in questo modo e fornisce anche alcuni risultati di benchmarking: stackoverflow.com/questions/415291/…
Demir

Questo è probabilmente il modo più semplice, ma non sarà efficace per array di grandi dimensioni, poiché Concat è implementato usando cicli foreach + yield (vedi fonte di riferimento). Una soluzione con BlockCopy sarà più veloce.
Tigrou,

1
Solo un piccolo avvertimento: se desideri solo scorrere il risultato combinato, non è necessario convertirlo in un array. L'operazione finale esegue una copia dell'array. Non dovrà farlo se si esegue l'iterazione tramite un IEnumerable <int>. Naturalmente, potrebbero esserci buone ragioni per avere un array.
Jonas il

82

Usa LINQ :

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

Tieni presente che ciò rimuoverà i duplicati. Se vuoi conservare i duplicati, usa Concat.


132
ATTENZIONE: l'Unione rimuoverà i duplicati.
Yogee,

1
@Yogee, facile da ricordare come è come in SQL e anche la nomenclatura è collegata alla teoria degli insiemi.
Zbigniew Wiadro,

8
poiché rimuoverà i duplicati, non potrà mai essere una risposta corretta.
Roni Tovi,

1
Vedo che Simon ha già menzionato la questione dell'Unione e l'approccio alternativo che ha suggerito. Non c'è bisogno di discuterne ulteriormente perché Simon sa a cosa sta rispondendo.
Sudhakar Chavali,

41

Se non vuoi rimuovere i duplicati, prova questo

Usa LINQ:

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

11

Innanzitutto, assicurati di porsi la domanda "Dovrei davvero utilizzare un array qui"?

A meno che tu non stia costruendo qualcosa in cui la velocità è della massima importanza, un elenco tipizzato, come List<int>probabilmente è la strada da percorrere. L'unica volta che uso mai gli array è per gli array di byte quando invio roba in rete. A parte questo, non li tocco mai.


Grande +1 qui. Si noti che la migliore pratica è quella di evitare di esporre List<T>in API pubbliche: blogs.msdn.com/b/kcwalina/archive/2005/09/26/474010.aspx
TrueWill

10

Più semplice sarebbe usare LINQ :

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

Per prima cosa converti gli array in elenchi e uniscili ... Dopo di che basta riconvertire l'elenco in un array :)


L'array non viene utilizzato direttamente. Hai usato List!
Behzad Ebrahimi,

7

Penso che tu possa usare Array.Copy per questo. Prende un indice di origine e un indice di destinazione, quindi dovresti essere in grado di aggiungere un array all'altro. Se hai bisogno di diventare più complesso che aggiungere semplicemente l'uno all'altro, questo potrebbe non essere lo strumento giusto per te.



4

Personalmente, preferisco le mie estensioni di lingua, che aggiungo o rimuovo a piacimento per la prototipazione rapida.

Di seguito è riportato un esempio di stringhe.

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

È molto più veloce di LINQ e Concat. Più velocemente, sta usando un IEnumerablewrapper di tipo personalizzato che memorizza riferimenti / puntatori di array passati e consente di eseguire il ciclo su tutta la raccolta come se fosse un array normale. (Utile in HPC, elaborazione grafica, rendering grafico ...)

Il tuo codice:

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

Per l'intero codice e una versione generica, consultare: https://gist.github.com/lsauer/7919764

Nota: restituisce un oggetto IEnumerable non esteso. Restituire un oggetto esteso è un po 'più lento.

Ho compilato tali estensioni dal 2002, con molti riconoscimenti rivolti a persone utili su CodeProject e 'Stackoverflow'. Rilascerò questi a breve e inserirò qui il link.


4

Tutti hanno già detto la loro, ma penso che questo sia più leggibile dell'approccio "usa come metodo di estensione":

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

Tuttavia, può essere utilizzato solo quando si riuniscono 2 array.


4

Questo è quello che mi è venuto in mente. Funziona per un numero variabile di matrici.

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

Solo per averlo notato come un'opzione: se gli array con cui stai lavorando sono di tipo primitivo - Boolean (bool), Char, SByte, Byte, Int16 (short), UInt16, Int32 (int), UInt32, Int64 (long ), UInt64, IntPtr, UIntPtr, Single o Double - allora potresti (o dovresti?) Provare a usare Buffer.BlockCopy . Secondo la pagina MSDN per la classe Buffer :

Questa classe offre prestazioni migliori per la manipolazione di tipi primitivi rispetto a metodi simili nella classe System.Array .

Usando l'esempio di C # 2.0 dalla risposta di @ OwenP come punto di partenza, funzionerebbe come segue:

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

C'è a malapena qualsiasi differenza nella sintassi tra il Buffer.BlockCopye Array.Copyche @OwenP utilizzato, ma questo dovrebbe essere più veloce (anche se di poco).


2

Nel caso in cui qualcun altro stia cercando come unire due array di byte di immagini:

        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

Ecco un semplice esempio usando Array.CopyTo. Penso che risponda alla tua domanda e fornisca un esempio dell'uso di CopyTo - Sono sempre perplesso quando devo usare questa funzione perché l'aiuto è un po 'poco chiaro - l'indice è la posizione nella matrice di destinazione in cui si verifica l'inserimento.

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

Immagino che non puoi renderlo molto più semplice.


1

Avevo bisogno di una soluzione per combinare un numero sconosciuto di matrici.

Sorpreso nessun altro ha fornito una soluzione usando SelectManycon params.

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

Se non desideri elementi distinti, rimuovi solo quelli distinti.

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

Nota: sicuramente non esiste alcuna garanzia di ordinazione quando si utilizza distinti.


0

Suppongo che tu stia utilizzando i tuoi tipi di array anziché gli array .NET incorporati:

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

Un altro modo per farlo sarebbe usare la classe ArrayList integrata.

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

Entrambi gli esempi sono 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 + " ");  

Utilizzando il codice sopra riportato, due array possono essere facilmente uniti.


0

Metodo creato ed estensione per gestire 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;
    }
}

0

Se si dispone degli array di origine in un array stesso, è possibile utilizzare 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);   

1
2
3
4
5
6

Probabilmente questo non è il metodo più veloce ma potrebbe adattarsi a seconda del caso d'uso.


-1

Questo codice funzionerà per tutti i casi:

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

Potresti aggiungere una descrizione più dettagliata della soluzione che fornisci?
abarisone,

1
Sebbene questo frammento di codice possa risolvere la domanda, inclusa una spiegazione aiuta davvero a migliorare la qualità del tuo post. Ricorda che stai rispondendo alla domanda per i lettori in futuro e quelle persone potrebbero non conoscere i motivi del tuo suggerimento sul codice.
gunr2171,

Questa sembra essere una fusione ordinata, che sebbene utile a sé stante (principalmente come parte di una strategia ricorsiva MergeSort), potrebbe essere più di quanto il PO chiedesse.
Darrel Hoffman,

Mentre questa soluzione funziona, avendo molte tecniche disponibili sin dall'introduzione di C # e VB.Net le persone potrebbero non preferire tali soluzioni.
Sudhakar Chavali,

-2

Prova questo:

ArrayLIst al = new ArrayList();
al.AddRange(array_1);
al.AddRange(array_2);
al.AddRange(array_3);
array_4 = al.ToArray();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.