.NETで2つの配列をマージする


225

2つの配列を取り、それらを1つの配列にマージする.NET 2.0の組み込み関数はありますか?

配列は両方とも同じタイプです。私のコードベース内で広く使用されている関数からこれらの配列を取得していますが、関数を変更してデータを別の形式で返すことができません。

可能であれば、これを実現するための独自の関数を作成しないようにしています。

回答:


118

配列の1つを操作できる場合は、コピーを実行する前に配列のサイズを変更できます。

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

それ以外の場合は、新しい配列を作成できます

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で利用可能なArrayメソッドの詳細


1
.NET 4.0についてのニュースはありますか?
Shimmy Weitzhandler 2010

4
Array.Resize実際には配列、それそれのコピーのサイズを変更しません。そのため、最初のパラメーターは参照渡しです(つまり、最初のコードはおそらくコンパイルされません)。
CodesInChaos

2
私はあなたの最初のコードを捨てます。これには利点がなく、IMOを読むのが難しくなります。
CodesInChaos

3
Array.Copyの2番目のコード例のパラメーターの順序が間違っていることに注意してください。Array.Copy(array1、newArray、0);を使用します。代わりに。
marco birchler 2013

.. List <byte> finalArray = new List <byte>();も実行できます。finalArray.AddRange(array1); finalArray.AddRange(array2); ==> finalArray.toArray();
セドリックボイビン2017

448

C#3.0では、LINQのConcatメソッドを使用して、これを簡単に実現できます。

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

C#2.0では、そのような直接的な方法はありませんが、Array.Copyはおそらく最良のソリューションです。

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

これは、独自のバージョンのを実装するために簡単に使用できますConcat


1
私はそのLINQ実装が好きです。私は本当にジャンプしてすぐにLINQに入る必要があります...
GEOCHET

1
リッチ、LINQ実装の最も優れた点は、簡潔であるだけでなく、IEnumerableに対して機能するため、2.0バージョンと同じくらい効率的です。
Brad Wilson、

この回答にはこの方法が含まれ、いくつかのベンチマーク結果も得られます。stackoverflow.com
Demir

これはおそらく最も簡単な方法ですが、Concatはforeachループ+ yieldを使用して実装されているため(参照ソースを参照)、大規模な配列では効率的ではありません。BlockCopyを使用したソリューションはより高速になります。
tigrou 2017年

1
ほんの少し前まで:結合された結果を反復処理するだけの場合は、配列に変換する必要はありません。その最後の操作は配列のコピーを行います。IEnumerable <int>を反復処理する場合は、その必要はありません。もちろん、それを配列にするのには十分な理由があります。
ジョナス

82

LINQを使用します。

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

重複を削除することに注意してください。重複を保持したい場合は、Concatを使用します。


132
注意:Unionは重複を削除します。
Yogee 2014年

1
@ Yogee、SQLのように覚えやすく、命名法は集合論と関連しています。
Zbigniew Wiadro 2015年

8
重複を削除するため、適切な答えにはなりません。
Roni Tovi 2016年

1
私はサイモンがすでに連合の問題と彼が提案した別のアプローチについて述べたのを見る。サイモンが答えを知っているので、それについてさらに議論する必要はありません。
Sudhakar Chavali

41

重複を削除したくない場合は、これを試してください

LINQを使用する:

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

11

まず、「ここで本当に配列を使用する必要があるのか​​」という質問を自問してください。

速度が最も重要なものを構築しているのでない限り、型付きリストは、List<int>おそらく進むべき道です。私がこれまでに配列を使用するのは、ネットワーク経由でデータを送信するときのバイト配列のみです。それ以外は、決して触れません。


ここで大きな+1。ベストプラクティスはList<T>、パブリックAPIで公開しないことです:blogs.msdn.com/b/kcwalina/archive/2005/09/26/474010.aspx
TrueWill

10

LINQを使用する方が簡単です。

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

最初に配列をリストに変換してマージします...その後、リストを配列に変換し直します:)


配列を直接使用することはありません。リストを使用しました!
Behzad Ebrahimi

7

これにはArray.Copyを使用できると思います。ソースインデックスと宛先インデックスを取得するため、1つの配列を他の配列に追加できるはずです。単に一方をもう一方に追加するよりも複雑にする必要がある場合、これは適切なツールではない可能性があります。



4

個人的には、ラピッドプロトタイピングのために自分で自由に追加または削除できる独自の言語拡張機能を好みます。

以下は文字列の例です。

//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やConcatよりもはるかに高速です。さらに速いのは、IEnumerable渡された配列の参照/ポインタを格納し、コレクション全体を通常の配列のようにループできるカスタムタイプラッパーを使用していることです。(HPC、グラフィックス処理、グラフィックスレンダリングで役立ちます...)

あなたのコード:

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

コード全体とジェネリックバージョンについては、https//gist.github.com/lsauer/7919764を参照してください。

注:これは、拡張されていないIEnumerableオブジェクトを返します。拡張オブジェクトを返すには少し時間がかかります。

2002年以降、このような拡張機能をコンパイルしました。多くのクレジットは、CodeProjectと 'Stackoverflow'の役立つ人々に提供されました。私はこれらをまもなくリリースし、リンクをここに配置します。


4

誰もがすでに発言権を持っていますが、これは「拡張メソッドとして使用する」アプローチよりも読みやすいと思います。

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

ただし、2つのアレイを組み合わせる場合にのみ使用できます。


4

これが私が思いついたものです。可変数の配列で機能します。

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

オプションとして注記しておきます。使用している配列がプリミティブ型である場合–ブール(ブール)、Char、SByte、Byte、Int16(short)、UInt16、Int32(int)、UInt32、Int64(long )、UInt64型、のIntPtr、UIntPtr、シングル、またはダブル- ?あなたは(または)を使用してみてください可能性がありBuffer.BlockCopyをBufferクラスのMSDNページによると:

このクラスは、System.Arrayクラスの同様のメソッドよりも、プリミティブ型を操作するためのパフォーマンスが向上します。

@OwenPの回答のC#2.0の例を出発点として使用すると、次のように機能します。

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

と@OwenPで使用されBuffer.BlockCopyArray.Copyいるとの間で構文にほとんど違いはありませんが、これはより速くなるはずです(わずかであっても)。


2

他の誰かが2つの画像バイト配列をマージする方法を探している場合:

        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

Array.CopyToを使用した簡単な例を次に示します。私はそれがあなたの質問に答え、CopyToの使用例を示していると思います-ヘルプが少し不明確なので、この関数を使用する必要があるときはいつも困惑します-インデックスは挿入が行われる宛先配列の位置です。

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

あなたはそれをもっと簡単にすることはできないと思います。


1

未知の数の配列を組み合わせるソリューションが必要でした。

を使用SelectManyして解決策を提供した人は他に誰もいないことに驚いたparams

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

個別のアイテムが必要ない場合は、個別を削除してください。

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

注:個別を使用する場合、順序の保証はありません。


0

組み込みの.NET配列ではなく、独自の配列型を使用していると想定しています。

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

これを行う別の方法は、組み込みのArrayListクラスを使用することです。

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

どちらの例も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 + " ");  

上記のコードを使用すると、2つの配列を簡単にマージできます。


0

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

配列自体にソース配列がある場合は、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

おそらくこれは最速の方法ではありませんが、ユースケースによっては適合する場合があります。


-1

このコードはすべてのケースで機能します。

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

提供するソリューションの説明を追加していただけますか?
abarisone 2015

1
このコードスニペットは問題を解決する可能性がありますが、説明を含めると、投稿の品質を向上させるのに役立ちます。あなたは将来の読者のための質問に答えていることを覚えておいてください、そしてそれらの人々はあなたのコード提案の理由を知らないかもしれません。
gunr2171

これはソートされたマージのようであり、それ自体は(主にMergeSort再帰的戦略の一部として)有用ですが、OPが求めていた以上のものである可能性があります。
ダレルホフマン

このソリューションは機能しますが、C#とVB.Netが導入されてから多くの手法を利用できるので、人々はそのようなソリューションを好まないかもしれません。
Sudhakar Chavali

-2

これを試して:

ArrayLIst al = new ArrayList();
al.AddRange(array_1);
al.AddRange(array_2);
al.AddRange(array_3);
array_4 = al.ToArray();
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.