質問
.NET 2.0には、2つの配列を取得して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);
他のヒント
C# 3.0 では、LINQ を使用できます。 連結 これを簡単に実現する方法:
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
.
使用 リンク:
var arr1 = new[] { 1, 2, 3, 4, 5 };
var arr2 = new[] { 6, 7, 8, 9, 0 };
var arr = arr1.Union(arr2).ToArray();
これにより重複が削除されることに注意してください。重複を保持したい場合は、Concat を使用します。
重複を削除したくない場合は、これを試してください
LINQ を使用します。
var arr1 = new[] { 1, 2, 3, 4, 5 };
var arr2 = new[] { 6, 7, 8, 9, 0 };
var arr = arr1.Concat(arr2).ToArray();
まず、「本当にここで配列を使用する必要があるのか?」という質問を必ず自問してください。
スピードが最重要視されるものを構築している場合を除き、次のような型付きリストを作成します。 List<int>
おそらくそれが進むべき道です。私が配列を使用するのは、ネットワーク経由でデータを送信するときのバイト配列の場合だけです。それ以外は決して触れません。
使うだけで簡単になります リンク:
var array = new string[] { "test" }.ToList();
var array1 = new string[] { "test" }.ToList();
array.AddRange(array1);
var result = array.ToArray();
まず配列をリストに変換し、それらをマージします...その後、リストを配列に変換して戻すだけです:)
使えると思います 配列.コピー このために。ソースインデックスと宛先インデックスを受け取るので、一方の配列をもう一方の配列に追加できるはずです。単純に一方を他方に追加するだけではなく、より複雑な処理を行う必要がある場合、これは適切なツールではない可能性があります。
宛先配列に十分なスペースがあると仮定すると、 Array.Copy()
働くでしょう。を使用してみることもできます List<T>
そしてその .AddRange()
方法。
個人的には、迅速なプロトタイピングのために自由に追加または削除できる独自の言語拡張機能の方が好きです。
以下は文字列の例です。
//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' で役立つ人々に多くの功績を残してきました。これらは近々リリースし、ここにリンクを貼ります。
すでに誰もが意見を述べていますが、これは「拡張メソッドとして使用する」アプローチよりも読みやすいと思います。
var arr1 = new[] { 1, 2, 3, 4, 5 };
var arr2 = new[] { 6, 7, 8, 9, 0 };
var arr = Queryable.Concat(arr1, arr2).ToArray();
ただし、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;
}
オプションとしてメモしておきます:操作している配列がプリミティブ型の場合 – Boolean (bool)、Char、SByte、Byte、Int16 (short)、UInt16、Int32 (int)、UInt32、Int64 (long)、UInt64、IntPtr、UIntPtr、Single 、または Double – それなら、使ってみてください (またはそうすべきですか?) Buffer.BlockCopy. 。MSDN ページによると、 バッファ クラス:
このクラスは、プリミティブ型を操作する場合、次の同様のメソッドよりも優れたパフォーマンスを提供します。 システム.配列 クラス。
@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);
構文の違いはほとんどありません Buffer.BlockCopy
そしてその Array.Copy
@OwenP が使用したものですが、これは (わずかであっても) 高速になるはずです。
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);
これ以上単純なことはできないと思います。
未知の数の配列を組み合わせるソリューションが必要でした。
他に誰も使用したソリューションを提供していないことに驚きました 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);
注記:明確に、distinct を使用するときに順序が保証されるわけではありません。
これが私が思いついたものです。可変数の配列に対して機能します。
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 }
組み込みの .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# です。
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 つの配列を簡単にマージできます。
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;
}
}
このコードはすべての場合に機能します。
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--];
}
}
これを試して:
ArrayLIst al = new ArrayList();
al.AddRange(array_1);
al.AddRange(array_2);
al.AddRange(array_3);
array_4 = al.ToArray();