Mesclando duas matrizes no .NET

225

Existe uma função interna no .NET 2.0 que terá duas matrizes e as mesclará em uma matriz?

As matrizes são do mesmo tipo. Estou obtendo essas matrizes de uma função amplamente usada na minha base de código e não posso modificar a função para retornar os dados em um formato diferente.

Estou procurando evitar escrever minha própria função para realizar isso, se possível.

kbrinley
fonte

Respostas:

118

Se você pode manipular uma das matrizes, pode redimensioná-la antes de executar a cópia:

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

Caso contrário, você pode criar uma nova matriz

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

Mais sobre os métodos de matriz disponíveis no MSDN .

Blair Conrad
fonte
1
E o .NET 4.0, alguma novidade?
Shimmy Weitzhandler
4
Observe que Array.Resize, na verdade, não redimensiona a matriz, ela a copia. É por isso que o primeiro parâmetro é by-ref (o que significa que seu primeiro código provavelmente não será compilado).
CodesInChaos
2
Eu jogaria fora seu primeiro pedaço de código. Não oferece uma vantagem e é mais difícil de ler IMO.
código é o seguinte
3
Observe que a ordem dos parâmetros no segundo exemplo de código para Array.Copy está incorreta. Use Array.Copy (array1, newArray, 0); em vez de.
Marco Birchler
Você também pode fazer .. List <byte> finalArray = new List <byte> (); finalArray.AddRange (array1); finalArray.AddRange (array2); ==> finalArray.toArray ();
Cédric Boivin
448

No C # 3.0, você pode usar o método Concat do LINQ para fazer isso facilmente:

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

No C # 2.0, você não tem uma maneira direta, mas o Array.Copy é provavelmente a melhor solução:

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

Isso poderia ser facilmente usado para implementar sua própria versão do Concat.

OwenP
fonte
1
Eu gosto da implementação do LINQ. Eu realmente preciso fazer o salto e entrar em LINQ breve ...
GEOCHET
1
Rico, a melhor parte da implementação do LINQ não é apenas concisa, como também é tão eficiente quanto a versão 2.0, pois funciona com o IEnumerable.
Brad Wilson
Esta resposta inclui esta maneira e também fornece alguns resultados de benchmarking: stackoverflow.com/questions/415291/…
Demir
Essa é provavelmente a maneira mais fácil, mas isso não será eficiente para matrizes grandes, pois o Concat é implementado usando loops de foreach + rendimento (consulte a fonte de referência). Uma solução com BlockCopy será mais rápida.
usar o seguinte
1
Apenas um pequeno alerta: se você deseja iterar apenas pelo resultado combinado, não é necessário convertê-lo em uma matriz. Essa operação final faz uma cópia de matriz. Não será necessário fazer isso se você iterar através de um IEnumerable <int>. Obviamente, pode haver boas razões para que seja uma matriz.
Jonas
82

Use LINQ :

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

Lembre-se de que isso removerá duplicatas. Se você deseja manter duplicatas, use Concat.

Simon B.
fonte
132
CUIDADO: O Union removerá duplicatas.
Yogee
1
@ Yogee, fácil de lembrar como é no SQL e também a nomenclatura está conectada à teoria dos conjuntos.
Zbigniew Wiadro 25/11
8
Como removerá duplicatas, nunca poderá ser uma resposta adequada.
Roni Tovi 13/03
1
Vejo que Simon já mencionou a questão da União e uma abordagem alternativa que ele sugeriu. Não há necessidade de discutir mais sobre isso, pois Simon sabe o que está respondendo.
Sudhakar Chavali 04/12/19
41

Se você não deseja remover duplicatas, tente isso

Use LINQ:

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

Primeiro, certifique-se de se perguntar "Eu realmente deveria estar usando uma matriz aqui"?

A menos que você esteja construindo algo em que a velocidade seja da maior importância, uma Lista digitada List<int>provavelmente será o caminho a percorrer. O único momento em que utilizo matrizes é para matrizes de bytes ao enviar coisas pela rede. Fora isso, eu nunca os toco.

CodesInChaos
fonte
Um +1 grande aqui. Observe que a prática recomendada é evitar a exposição List<T>em APIs públicas: blogs.msdn.com/b/kcwalina/archive/2005/09/26/474010.aspx
TrueWill
10

Mais fácil seria usar o LINQ :

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

Primeiro converta as matrizes em listas e mesclá-las ... Depois disso, basta converter a lista novamente em uma matriz :)

Angelo Ortega
fonte
Você não é usado diretamente da matriz. Você usou a lista!
Behzad Ebrahimi
7

Eu acho que você pode usar Array.Copy para isso. É necessário um índice de origem e destino, para que você possa anexar uma matriz à outra. Se você precisar se tornar mais complexo do que apenas anexar um ao outro, talvez essa não seja a ferramenta certa para você.

GEOCHET
fonte
5

Supondo que a matriz de destino tenha espaço suficiente, Array.Copy()funcionará. Você também pode tentar usar a List<T>e seu .AddRange()método.

Joel Coehoorn
fonte
4

Pessoalmente, prefiro minhas próprias Extensões de Idioma, que adiciono ou removo à vontade para prototipagem rápida.

A seguir, um exemplo para seqüências de caracteres.

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

É muito mais rápido que o LINQ e o Concat. Mais rápido ainda, está usando um costumeIEnumerable invólucro de tipo que armazena referências / ponteiros de matrizes passadas e permite fazer um loop por toda a coleção como se fosse uma matriz normal. (Útil em HPC, Processamento gráfico, Renderização gráfica ...)

Seu código:

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

Para o código inteiro e uma versão genérica, consulte: https://gist.github.com/lsauer/7919764

Nota: Isso retorna um objeto IEnumerable não estendido. Retornar um objeto estendido é um pouco mais lento.

Compilei essas extensões desde 2002, com muitos créditos destinados a pessoas úteis no CodeProject e 'Stackoverflow'. Os lançarei em breve e colocarei o link aqui em cima.

Lorenz Lo Sauer
fonte
4

Todo mundo já deu a sua opinião, mas acho isso mais legível do que a abordagem "usar como método de extensão":

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

No entanto, ele só pode ser usado ao reunir 2 matrizes.

John Reilly
fonte
4

Isto é o que eu vim com. Funciona para um número variável de matrizes.

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

Apenas para que seja anotada como uma opção: se as matrizes com as quais você estiver trabalhando forem de um tipo primitivo - Boolean (bool), Char, SByte, Byte, Int16 (abreviado), UInt16, Int32 (int), UInt32, Int64 (long ), UInt64, IntPtr, UIntPtr, Single ou Double - então você pode (ou deveria?) Tentar usar o Buffer.BlockCopy . De acordo com a página MSDN da classe Buffer :

Essa classe fornece melhor desempenho para manipular tipos primitivos do que métodos semelhantes na classe System.Array .

Usando o exemplo C # 2.0 da resposta do @ OwenP como ponto de partida, ele funcionaria da seguinte maneira:

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

Quase não há diferença na sintaxe entre Buffer.BlockCopya Array.Copyque o @OwenP usou, mas isso deve ser mais rápido (mesmo que apenas um pouco).

Solomon Rutzky
fonte
2

Caso outra pessoa esteja procurando como mesclar duas matrizes de bytes de imagem:

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

Aqui está um exemplo simples usando Array.CopyTo. Eu acho que ele responde à sua pergunta e fornece um exemplo do uso de CopyTo - eu sempre fico confuso quando preciso usar essa função porque a ajuda é um pouco clara - o índice é a posição na matriz de destino onde a inserção ocorre.

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

Eu acho que você não pode simplificar muito.

pasx
fonte
1

Eu precisava de uma solução para combinar um número desconhecido de matrizes.

Surpreendido ninguém forneceu uma solução usando SelectManycom params.

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

Se você não deseja itens distintos, basta remover distintos.

 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: Definitivamente, não há garantia de pedido ao usar distintos.

Simon_Weaver
fonte
0

Suponho que você esteja usando seus próprios tipos de matriz em oposição às matrizes .NET internas:

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

Outra maneira de fazer isso seria usar a classe ArrayList incorporada.

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

Ambos os exemplos são c #.

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

Usando o código acima, duas matrizes podem ser facilmente mescladas.

vikasse
fonte
0

Método criado e de extensão para manipular 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
fonte
0

Se você tiver as matrizes de origem em uma matriz, poderá usar o 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

Provavelmente, esse não é o método mais rápido, mas pode ser adequado, dependendo do caso de uso.

schoetbi
fonte
-1

Este código funcionará para todos os casos:

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
fonte
Você poderia adicionar mais descrição sobre a solução que você fornece?
Abarisone
1
Embora esse trecho de código possa resolver a questão, incluir uma explicação realmente ajuda a melhorar a qualidade da sua postagem. Lembre-se de que você está respondendo à pergunta dos leitores no futuro e essas pessoas podem não saber os motivos da sua sugestão de código.
precisa saber é o seguinte
Parece ser uma mesclagem classificada, que, embora útil por si só (principalmente como parte de uma estratégia recursiva do MergeSort), pode ser mais do que o OP solicitava.
Darrel Hoffman
Enquanto essa solução funciona, com muitas técnicas disponíveis desde a introdução do C # e do VB.Net, as pessoas podem não preferir essas soluções.
Sudhakar Chavali 04/12/19
-2

Tente o seguinte:

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