关于C#:在.NET中合并两个数组

关于C#:在.NET中合并两个数组

Merging two arrays in .NET

.NET 2.0中是否有内置函数将两个数组合并为一个数组?

数组都是相同的类型。 我是从代码库中广泛使用的函数获取这些数组的,无法修改该函数以其他格式返回数据。

我希望避免编写自己的函数来完成此操作(如果可能)。


在C#3.0中,可以使用LINQ的Concat方法轻松完成此操作:

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

在C#2.0中,您没有直接的方法,但是Array.Copy可能是最好的解决方案:

1
2
3
4
5
6
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
2
3
4
5
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);

否则,您可以制作一个新数组

1
2
3
4
5
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上可用数组方法的更多信息。


使用LINQ:

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

请记住,这将删除重复项。如果要保留重复项,请使用Concat。


如果您不想删除重复项,请尝试此操作

使用LINQ:

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


首先,请确保您问自己一个问题:"我真的应该在这里使用数组吗?"?

除非您要构建对速度至关重要的东西,否则使用List之类的类型化List可能是可行的方法。通过网络发送内容时,我唯一一次使用数组是用于字节数组。除此之外,我从未碰过它们。


使用LINQ更容易:

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

首先将数组转换为列表并将其合并...之后,只需将列表转换回数组即可:)


我认为您可以为此使用Array.Copy。它需要一个源索引和一个目标索引,因此您应该能够将一个数组附加到另??一个数组。如果您需要的不只是将一个附加到另一个上而变得更加复杂,那么这可能不是适合您的工具。


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


就个人而言,我更喜欢自己的语言扩展,可以随意添加或删除这些语言扩展以快速进行原型制作。

以下是字符串的示例。

1
2
3
4
5
6
7
8
9
10
11
12
//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,图形处理,图形渲染中很有用...)

您的代码:

1
2
3
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"上的有用人员。我将在短期内发布这些链接,并将链接放在此处。


每个人都已经发表了意见,但是我认为这比"用作扩展方法"方法更具可读性:

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

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


这就是我想出的。 适用于可变数量的数组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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;
    }

...

1
2
3
4
5
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 }

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
        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.webp"), ImageFormat.Png);
                    MemoryStream mergedImageStream = new MemoryStream();
                    imgBase.Save(mergedImageStream, ImageFormat.Png);
                    mergedImageData = mergedImageStream.ToArray();
                    mergedImageStream.Close();
                }
            }
            return mergedImageData;
        }

只是将其记录为一个选项:如果您使用的数组是基本类型Boolean(布尔型),Char,SByte,Byte,Int16(短型),UInt16,Int32(int),UInt32,Int64(长型) ,UInt64,IntPtr,UIntPtr,Single或Double,则可以(或应该?)尝试使用Buffer.BlockCopy。根据Buffer类的MSDN页面:

This class provides better performance for manipulating primitive types than similar methods in the System.Array class.

以@OwenP的答案中的C#2.0示例作为起点,它的工作方式如下:

1
2
3
4
5
6
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);

@xOwenP使用的Buffer.BlockCopyArray.Copy在语法上几乎没有任何区别,但这应该更快(即使只是一点点)。


这是一个使用Array.CopyTo的简单示例。
我认为它回答了您的问题,并提供了一个CopyTo用法的示例-当我需要使用此函数时,我总是很困惑,因为帮助有点不清楚-索引是目标数组在其中发生插入的位置。

1
2
3
4
5
6
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);

我想你再简单不过了。


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

惊讶的是没有其他人提供使用SelectManyparams的解决方案。

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

如果您不希望使用不重复项,则只需删除不重复项即可。

1
2
3
4
5
 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时,绝对不能保证订购。


创建和扩展方法来处理null

1
2
3
4
5
6
7
8
9
10
11
12
13
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;
    }
}

我假设您使用的是自己的数组类型,而不是内置的.NET数组:

1
2
3
4
5
6
7
8
9
10
11
12
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类。

1
2
3
4
5
6
7
8
9
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#。


1
2
3
4
5
6
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 +"");

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


此代码适用于所有情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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--];
    }
}


尝试这个:

1
2
3
4
5
ArrayLIst al = new ArrayList();
al.AddRange(array_1);
al.AddRange(array_2);
al.AddRange(array_3);
array_4 = al.ToArray();


推荐阅读

    linux常见操作命令?

    linux常见操作命令?,系统,工作,信息,管理,地址,命令,目录,单位,数据,标准,lin

    红帽子linux操作命令?

    红帽子linux操作命令?,服务,系统,密码,环境,信息,通用,软件,状态,设备,命令,

    linux查看函数命令?

    linux查看函数命令?,系统,信息,名称,命令,位置,情况,公用,名字,标准,资料,lin

    linux合并命令怎么用?

    linux合并命令怎么用?,地址,文件,位置,工作,电脑,代码,系统,命令,文档,内容,L

    linux日常操作命令?

    linux日常操作命令?,工作,系统,地址,信息,命令,目录,基础,管理,操作,功能,lin

    查看linux类型命令?

    查看linux类型命令?,系统,信息,命令,状态,数据,数字,情况,地址,类型,文件,lin

    linux删除类型命令?

    linux删除类型命令?,系统,档案,命令,文件,名称,环境,数据,不了,目录,文件夹,

    linux合并保存命令行?

    linux合并保存命令行?,文件,地址,代码,工作,命令,两个,内容,目录,方法,文件

    go操作linux命令?

    go操作linux命令?,系统,工具,环境,软件,标准,网上,最新,信息,设备,电脑,Linux

    linux命令操作vim?

    linux命令操作vim?,系统,地址,工作,命令,模式,标准,信息,入口,连续,时间,Linu

    linux操作不了命令?

    linux操作不了命令?,系统,密码,不了,命令,位置,信息,情况,网络,地址,定期,lin

    linux运维操作命令?

    linux运维操作命令?,系统,网络,基础,标准,工具,信息,工作,命令,软件,数据,lin

    linux命令行常见操作?

    linux命令行常见操作?,系统,工作,地址,管理,信息,命令,目录,一致,基础,标准,l

    linux清空操作命令?

    linux清空操作命令?,系统,数据,命令,名称,不了,文件夹,文件,环境,回收站,目

    调用函数命令linux?

    调用函数命令linux?,系统,管理,网络,通用,统一,观察,地址,代码,设备,地方,怎

    查看linux库类型命令?

    查看linux库类型命令?,系统,工作,信息,状态,电脑,命令,工具,代码,地址,发行,

    linux安装操作命令?

    linux安装操作命令?,系统,工作,地址,工具,服务,情况,信息,命令,最新,管理,lin

    linux文件夹合并命令?

    linux文件夹合并命令?,文件,对比,第一,下来,命令,文件夹,两个,字段,内容,数

    linux操作系mv命令?

    linux操作系mv命令?,名字,系统,软件,文件,命令,信息,地址,目录,文件夹,源文

    linux操作命令大全图?

    linux操作命令大全图?,工作,地址,系统,信息,命令,目录,控制台,功能,操作,内