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

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

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

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

【问题讨论】:

    标签: c# .net arrays


    【解决方案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。
    • 这个答案包括这种方式,也给出了一些基准测试结果:stackoverflow.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; 可能是要走的路。我唯一一次使用数组是在通过网络发送东西时使用字节数组。除此之外,我从不碰它们。

      【讨论】:

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

              【讨论】:

                【解决方案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();
                                    

                                    【讨论】:

                                      猜你喜欢
                                      • 2010-12-31
                                      • 2013-08-26
                                      • 2011-02-22
                                      • 2016-10-07
                                      • 1970-01-01
                                      • 1970-01-01
                                      • 1970-01-01
                                      • 1970-01-01
                                      • 1970-01-01
                                      相关资源
                                      最近更新 更多