.NET 2.0中是否有一个内置函数,可以将两个数组合并成一个数组?

这两个数组具有相同的类型。我从代码库中广泛使用的函数中获得这些数组,并且不能修改该函数以以不同的格式返回数据。

如果可能的话,我希望避免编写自己的函数来完成这个任务。


我认为你可以使用数组。收到。它有一个源索引和一个目标索引,因此您应该能够将一个数组附加到另一个数组。如果您需要更复杂的操作,而不仅仅是将一个附加到另一个,那么这个工具可能不适合您。

假设目标数组有足够的空间,array . copy()将工作。您也可以尝试使用List<T>及其. addrange()方法。

我假设你正在使用自己的数组类型,而不是内置的。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#。

如果你可以操作其中一个数组,你可以在执行复制之前调整它的大小:

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方法。

首先,一定要问自己一个问题:“我真的应该在这里使用数组吗?”

除非您正在构建速度最重要的东西,否则类型化的List,如List<int>可能是最好的方法。我唯一一次使用数组是在通过网络发送东西时使用字节数组。除此之外,我从不碰它们。

在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中,你没有这样直接的方法,但是数组。复制可能是最好的解决方案:

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版本。

试试这个:

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

下面是一个使用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);

我想你不能再简单了。

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

使用上面的代码可以很容易地合并两个数组。

就我个人而言,我更喜欢我自己的语言扩展,我可以随意添加或删除它以快速创建原型。

下面是一个字符串的例子。

//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类型包装器,它存储传递数组的引用/指针,并允许对整个集合进行循环,就像它是一个普通数组一样。(适用于高性能计算,图形处理,图形渲染…)

你的代码:

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”上的乐于助人的人。我很快就会发布这些,并把链接放在这里。

使用LINQ:

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 array = new string[] { "test" }.ToList();
var array1 = new string[] { "test" }.ToList();
array.AddRange(array1);
var result = array.ToArray();

首先将数组转换为列表并合并它们…之后,只需将列表转换回数组:)

如果有人正在寻找如何合并两个图像字节数组:

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

这段代码将适用于所有情况:

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

每个人都有自己的说法,但我认为这比“作为扩展方法使用”方法更具可读性:

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

但是,它只能在将2个数组组合在一起时使用。

只是有一个选项:如果你正在使用的数组是一个基本类型-布尔(bool), Char, SByte, Byte, Int16(短),UInt16, Int32 (int), UInt32, Int64(长),UInt64, IntPtr, UIntPtr,单,或双-那么你可以(或应该?)尝试使用Buffer.BlockCopy。根据Buffer类的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。复制@OwenP使用的,但这应该更快(即使只有一点点)。

如果你不想删除重复的,那么试试这个

使用LINQ:

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

创建和扩展方法来处理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;
    }
}

我需要一个解决方案来组合未知数量的数组。

令人惊讶的是没有人提供一个解决方案使用SelectMany与参数。

 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 }

如果你在一个数组中有源数组,你可以使用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

这可能不是最快的方法,但根据用例可能适合。

连接多个数组的简单代码:

string[] arr1 = ...
string[] arr2 = ...
string[] arr3 = ...    
List<string> arr = new List<string>(arr1.Length + arr2.Length + arr3.Length);
arr.AddRange(arr1);
arr.AddRange(arr2);
arr.AddRange(arr3);
string[] result = arr.ToArray();

这是另一种方法:

public static void ArrayPush<T>(ref T[] table, object value)
{
    Array.Resize(ref table, table.Length + 1); // Resizing the array for the cloned length (+-) (+1)
    table.SetValue(value, table.Length - 1); // Setting the value for the new element
}

public static void MergeArrays<T>(ref T[] tableOne, T[] tableTwo) {
    foreach(var element in tableTwo) {
        ArrayPush(ref tableOne, element);
    }
}

下面是代码片段/示例

string[] names1 = new string[] { "Ava", "Emma", "Olivia" };
string[] names2 = new string[] { "Olivia", "Sophia", "Emma" };
List<string> arr = new List<string>(names1.Length + names2.Length);
arr.AddRange(names1);
arr.AddRange(names2);
string[] result = arr.Distinct().ToArray();
foreach(string str in result)
{
    Console.WriteLine(str.ToString());
}

Console.ReadLine();

我想找到一种不使用数组本身以外的任何库或功能的方法。

前两个示例主要用于从头读取逻辑,但我也想知道是否会根据情况而有性能变化。

第三个例子是最实际的选择。

// Two for-loops
private static int[] MergedArrays_1(int[] a, int[] b)
{
    int[] result = new int[a.Length + b.Length];
    for (int i = 0; i < a.Length; i++)
    {
        result[i] = a[i];
    }
    for (int i = a.Length; i < result.Length; i++)
    {
        result[i] = b[i - a.Length];
    }
    return result;
}

// One for-loop
private static int[] MergedArrays_2(int[] a, int[] b)
{
    int[] results = new int[a.Length + b.Length];
    for (int i = 0; i < results.Length; i++)
    {
        results[i] = (i < a.Length) ? a[i] : b[i - a.Length];
    }
    return results;
}

// Array Method
private static int[] MergedArrays_3(int[] a, int[] b)
{
    int[] results = new int[a.Length + b.Length];
    a.CopyTo(results, 0);
    b.CopyTo(results, a.Length);
    return results;
}

最后,我做了第四个例子,可以合并多个数组,使用params关键字。

int[] result = MultipleMergedArrays(arrayOne, arrayTwo, arrayThree);
private static int[] MultipleMergedArrays(params int[][] a)
{
    // Get Length
    int resultsLength = 0;
    for (int row = 0; row < a.GetLength(0); row++)
    {
        resultsLength += a.Length;
    }

    // Initialize
    int[] results = new int[resultsLength];

    // Add Items
    int index = 0;
    for (int row = 0; row < a.GetLength(0); row++)
    {
        a[row].CopyTo(results, index);
        index += a[row].Length;
    }
    return results;
}

当使用参数时,它的工作方式是将一维数组传递到锯齿数组中。

GetLength(0)返回锯齿状数组中包含的数组数。

该代码首先计算所有数组的Length,然后根据该大小初始化一个新数组,并开始使用CopyTo()方法将整个数组添加到新的结果数组中,同时将每个添加的数组的Length添加到索引计数器中。

PS:在合并时,有时需要从数组中删除空项或某些项。

private static int[] RemoveEmpty(int[] array)
{
    int count = 0;
    for (int i = 0; i < array.Length; i++)
    {
        if (array[i] == 0) count++;
    }

    int[] result = new int[array.Length - count];

    count = 0;
    for (int i = 0; i < array.Length; i++)
    {
        if (array[i] == 0) continue;
        result[count] = array[i];
        count++;
    }

    return result;
}

这个函数可以与上面的函数结合使用。

它接受一个数组,计算匹配为0的项的数量。并创建一个大小合适的新数组。然后计数器被回收并用作索引,用于将输入数组的值放入新的更小的结果数组中。 当一个项匹配0时,它将跳过该循环中的其余代码,并继续下一轮循环,不增加整数计数器。

自从。net 5以来,我们现在有了AllocateUnitializedArray,它可能会为建议的解决方案增加额外的(小)性能改进:

public static T[] ConcatArrays<T>(IEnumerable<T[]> arrays)
{
    var result = GC.AllocateUnitializedArray<T>(arrays.Sum(a => a.Length));
    var offset = 0;
    foreach (var a in arrays)
    {
        a.CopyTo(result, offset);
        offset += a.Length;
    }
    return result;
}