在 .NET 中合并两个数组

Posted

技术标签:

【中文标题】在 .NET 中合并两个数组【英文标题】:Merging two arrays in .NET 【发布时间】:2010-09-08 17:20:15 【问题描述】:

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

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

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

【问题讨论】:

【参考方案1】:

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

【讨论】:

我喜欢那个 LINQ 实现。我真的需要尽快跳入 LINQ... 丰富,LINQ 实现最好的部分不仅是简洁,而且与 2.0 版本一样高效,因为它适用于 IEnumerable。 这个答案包括这种方式,也给出了一些基准测试结果:***.com/questions/415291/… 这可能是最简单的方法,但对于大型数组来说这不会是有效的,因为 Concat 是使用 foreach 循环 + yield 实现的(参见参考源)。使用 BlockCopy 的解决方案会更快。 请注意:如果您只想遍历组合结果,则无需将其转换为数组。最后的操作执行数组复制。如果您遍历 IEnumerable,则不必这样做。当然,有充分的理由让它成为一个数组。【参考方案2】:

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

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

More on available Array methods on MSDN.

【讨论】:

.NET 4.0 怎么样,有什么消息吗? 请注意,Array.Resize 实际上并没有调整数组的大小,而是复制它。这就是为什么第一个参数是 by-ref(这意味着您的第一个代码可能无法编译)。 我只想扔掉你的第一段代码。它没有任何优势,而且更难阅读 IMO。 请注意,Array.Copy 的第二个代码示例中的参数顺序是错误的。使用 Array.Copy(array1, newArray, 0);而是。 你也可以这样做.. List finalArray = new List(); finalArray.AddRange(array1); finalArray.AddRange(array2); ==>finalArray.toArray();【参考方案3】:

使用LINQ:

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

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

【讨论】:

注意:Union 将删除重复项。 @Yogee,就像在 SQL 中一样容易记住,而且命名法与集合论有关。 因为它会删除重复项,所以它永远不会是一个正确的答案。 我看到西蒙已经提到了联合问题和他建议的替代方法。无需进一步讨论,因为西蒙知道他在回答什么。【参考方案4】:

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

使用 LINQ:

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

【讨论】:

【参考方案5】:

首先,确保你问自己“我真的应该在这里使用数组吗”这个问题?

除非您正在构建速度至关重要的东西,否则键入列表,如List&lt;int&gt; 可能是要走的路。我唯一一次使用数组是在通过网络发送东西时使用字节数组。除此之外,我从不碰它们。

【讨论】:

在这里大 +1。请注意,最佳做法是避免在公共 API 中公开 List&lt;T&gt;:blogs.msdn.com/b/kcwalina/archive/2005/09/26/474010.aspx【参考方案6】:

使用LINQ 会更容易:

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

首先将数组转换为列表并将它们合并...然后将列表转换回数组:)

【讨论】:

你没有直接使用数组。您使用了列表!【参考方案7】:

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

【讨论】:

【参考方案8】:

每个人都已经有了自己的发言权,但我认为这比“用作扩展方法”的方法更具可读性:

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

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

【讨论】:

【参考方案9】:

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

【讨论】:

【参考方案10】:

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

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 

【讨论】:

【参考方案11】:

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

以下是字符串的示例。

//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 和 '***' 上的有帮助的人。我会尽快发布这些并将链接放在这里。

【讨论】:

【参考方案12】:

只是将其作为一个选项注明:如果您正在使用的数组是原始类型 - Boolean (bool)、Char、SByte、Byte、Int16 (short)、UInt16、Int32 (int)、UInt32、 Int64 (long)、UInt64、IntPtr、UIntPtr、Single 或 Double - 那么您可以(或应该?)尝试使用 Buffer.BlockCopy。根据 Buffer 类的 MSDN 页面:

与System.Array 类中的类似方法相比,此类在操作原始类型方面提供了更好的性能。

使用@OwenP 的answer 中的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 和 @OwenP 使用的 Array.Copy 在语法上几乎没有任何区别,但这应该更快(即使只有一点点)。

【讨论】:

【参考方案13】:

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

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

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

如果您不想要不同的项目,只需删除 distinct。

 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 时绝对不能保证有序。

【讨论】:

【参考方案14】:

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

        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;
        

【讨论】:

【参考方案15】:

如果您在数组本身中有源数组,您可以使用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

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

【讨论】:

【参考方案16】:

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

我猜你再简单不过了。

【讨论】:

【参考方案17】:

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

【讨论】:

【参考方案18】:
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 + " ");  

使用上面的代码可以轻松合并两个数组。

【讨论】:

【参考方案19】:

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

【讨论】:

【参考方案20】:
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();

【讨论】:

请添加更多详细信息以扩展您的答案,例如工作代码或文档引用。【参考方案21】:

此代码适用于所有情况:

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

【讨论】:

能否请您添加更多关于您提供的解决方案的描述? 虽然这段代码 sn-p 可以解决问题,including an explanation 确实有助于提高您的帖子质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。 这似乎是一个排序合并,虽然它本身很有用(主要作为 MergeSort 递归策略的一部分),但可能比 OP 所要求的要多。 虽然此解决方案有效,但自从引入 C# 和 VB.Net 以来,有很多可用的技术,人们可能不喜欢这样的解决方案。【参考方案22】:

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

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

【讨论】:

【参考方案23】:

这是另一种方法:)

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

这里是snippet/example

【讨论】:

【参考方案24】:

试试这个:

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

【讨论】:

以上是关于在 .NET 中合并两个数组的主要内容,如果未能解决你的问题,请参考以下文章

在 .NET 中有效地合并字符串数组,保持不同的值

在 ActionScript (3.0) 中干净地合并两个数组?

matlab中怎样把两个2维数组合并在一起

在 JavaScript 中合并两个对象(NodeList)数组

在laravel中合并两个数组值

LeetCode88. 合并两个有序数组