如何在C#中连接两个数组?

hwi*_*ers 242 c#

int[] x = new int [] { 1, 2, 3};
int[] y = new int [] { 4, 5 };

int[] z = // your answer here...

Debug.Assert(z.SequenceEqual(new int[] { 1, 2, 3, 4, 5 }));
Run Code Online (Sandbox Code Playgroud)

-

现在我用

int[] z = x.Concat(y).ToArray();
Run Code Online (Sandbox Code Playgroud)

有更简单或更有效的方法吗?

Zed*_*Zed 308

var z = new int[x.Length + y.Length];
x.CopyTo(z, 0);
y.CopyTo(z, x.Length);
Run Code Online (Sandbox Code Playgroud)

  • @manthrax - >在它的辩护中,C#倾向于支持比数组更强大的列表.似乎使用数组的唯一功能目的是Interop调用(Unmanaged C++). (5认同)
  • 这并不奇怪.数组是不可变的,列表不是.除非调用TrimExcess(在ToList中不会发生),否则List使用的内存多于数组 (4认同)
  • 访问数据时,数组也比列表快,因为列表只是将数组包装在里面,并且有调用索引器的开销。 (3认同)
  • @LeviFuller - 许多系统例程返回数组而不是列表很奇怪。例如`System.IO.Directory.GetFiles()` 返回一个字符串数组。 (2认同)

Adr*_*der 79

试试这个:

List<int> list = new List<int>();
list.AddRange(x);
list.AddRange(y);
int[] z = list.ToArray();
Run Code Online (Sandbox Code Playgroud)

  • 这比x.Concat(y)更有效吗?它有效,所有,我只是想知道是否有更好的东西? (7认同)
  • 你可能想要第一行List <int> list = new List <int>(x.Length + y.Length); 避免在调用AddRange时可能发生的调整大小 (6认同)
  • 甚至`List <int> list = new List <int>(x);` (5认同)
  • @Mathew Scharley.问题是要求更有效的解决方案.我知道标题听起来像任何旧的组合都会做,但完整的问题超出了这个范围.阅读一些答案我觉得有些人正在回答这个问题.所以我认为这个答案应该提到效率,如果它值得赞成,因为这似乎是问题的关键. (5认同)
  • 事实证明,AddRange实际上是一个非常昂贵的过程,因此该板上的第一个答案应该是首选方法:http://www.dotnetperls.com/insertrange (2认同)

Mar*_*ell 47

你可以写一个扩展方法:

public static T[] Concat<T>(this T[] x, T[] y)
{
    if (x == null) throw new ArgumentNullException("x");
    if (y == null) throw new ArgumentNullException("y");
    int oldLen = x.Length;
    Array.Resize<T>(ref x, x.Length + y.Length);
    Array.Copy(y, 0, x, oldLen, y.Length);
    return x;
}
Run Code Online (Sandbox Code Playgroud)

然后:

int[] x = {1,2,3}, y = {4,5};
int[] z = x.Concat(y); // {1,2,3,4,5}
Run Code Online (Sandbox Code Playgroud)

  • 是的,我会在大多数情况下愉快地使用它.但是他们有很多开销.这取决于; 98%的时间间隔是开销很好.但是,如果你在2%,那么一些直接的memcopy /数组工作是很方便的. (2认同)

dee*_*ee1 36

我选择了一个更通用的解决方案,它允许连接任意一组相同类型的一维数组.(我一次连接3+.)

我的功能:

    public static T[] ConcatArrays<T>(params T[][] list)
    {
        var result = new T[list.Sum(a => a.Length)];
        int offset = 0;
        for (int x = 0; x < list.Length; x++)
        {
            list[x].CopyTo(result, offset);
            offset += list[x].Length;
        }
        return result;
    }
Run Code Online (Sandbox Code Playgroud)

用法:

        int[] a = new int[] { 1, 2, 3 };
        int[] b = new int[] { 4, 5, 6 };
        int[] c = new int[] { 7, 8 };
        var y = ConcatArrays(a, b, c); //Results in int[] {1,2,3,4,5,6,7,8}
Run Code Online (Sandbox Code Playgroud)


小智 31

就是这个:

using System.Linq;

int[] array1 = { 1, 3, 5 };
int[] array2 = { 0, 2, 4 };

// Concatenate array1 and array2.
var result1 = array1.Concat(array2);
Run Code Online (Sandbox Code Playgroud)

  • 你的意思是`int [] result = array1.ToList().Concat(array2.ToList()).toArray();`你不能直接在数组上应用Concat我相信 (4认同)
  • 这个解决方案 - z = x.Concat(y) - 在上面的原始问题中提到. (4认同)
  • 这就是在没有 `toArray()` 的情况下发生的情况 `不能将类型 'System.Collections.Generic.IEnumerable&lt;string&gt;' 隐式转换为 'string[]'。存在显式转换(您是否缺少强制转换?)` (2认同)
  • 这不是直接的答案。OP要求提供“ int [] result =?”,您将答案隐藏在“ var”后面,因为您的结果将是“ IEnumerable &lt;int&gt;”,而不是“ int []”。(为什么我不喜欢方法返回上的`var`的原因之一) (2认同)
  • 此方法是问题中使用的方法,因此此答案不提供任何新信息,并且没有`.ToArray()`调用,此代码将不会返回实际的数组,因此它也是错误的答案。 (2认同)

Mik*_*Two 10

您可以将ToArray()调用结束.有没有理由在调用Concat之后需要它成为一个数组?

调用Concat会在两个数组上创建一个迭代器.它不会创建新数组,因此您没有为新数组使用更多内存.当你调用ToArray时,你实际上创建了一个新数组并占用了新数组的内存.

因此,如果您只需要轻松迭代两者,那么只需调用Concat即可.


Jod*_*ell 10

更高效的(快)使用Buffer.BlockCopyArray.CopyTo

int[] x = new int [] { 1, 2, 3};
int[] y = new int [] { 4, 5 };

int[] z = new int[x.Length + y.Length];
var byteIndex = x.Length * sizeof(int);
Buffer.BlockCopy(x, 0, z, 0, byteIndex);
Buffer.BlockCopy(y, 0, z, byteIndex, y.Length * sizeof(int));
Run Code Online (Sandbox Code Playgroud)

我编写了一个简单的测试程序来“预热抖动”,在发布模式下编译并在我的机器上运行它,而没有附加调试器。

对于问题中示例的 10,000,000 次迭代

Concat 耗时 3088 毫秒

CopyTo 耗时 1079 毫秒

块复制耗时 603 毫秒

如果我将测试数组更改为从 0 到 99 的两个序列,那么我会得到与此类似的结果,

Concat 耗时 45945 毫秒

CopyTo 耗时 2230 毫秒

块复制耗时 1689 毫秒

从这些结果中,我可以断言CopyToBlockCopy方法明显更有效Concat,而且,如果性能是目标,BlockCopy则价值超过CopyTo

要注意这个答案,如果性能无关紧要,或者迭代次数很少,请选择您认为最简单的方法。Buffer.BlockCopy确实提供了一些超出此问题范围的类型转换实用程序。


ama*_*ate 7

我知道OP对性能只是有点好奇.较大的数组可能会得到不同的结果(请参阅@kurdishTree).而这通常无关紧要(@ jordan.peoples).尽管如此,我很好奇,因此失去了理智(正如@TigerShark所解释的那样)......我的意思是我根据原始问题编写了一个简单的测试......以及所有答案......

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace concat
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] x = new int [] { 1, 2, 3};
            int[] y = new int [] { 4, 5 };


            int itter = 50000;
            Console.WriteLine("test iterations: {0}", itter);

            DateTime startTest = DateTime.Now;
            for(int  i = 0; i < itter; i++)
            {
                int[] z;
                z = x.Concat(y).ToArray();
            }
            Console.WriteLine ("Concat Test Time in ticks: {0}", (DateTime.Now - startTest).Ticks );

            startTest = DateTime.Now;
            for(int  i = 0; i < itter; i++)
            {
                var vz = new int[x.Length + y.Length];
                x.CopyTo(vz, 0);
                y.CopyTo(vz, x.Length);
            }
            Console.WriteLine ("CopyTo Test Time in ticks: {0}", (DateTime.Now - startTest).Ticks );

            startTest = DateTime.Now;
            for(int  i = 0; i < itter; i++)
            {
                List<int> list = new List<int>();
                list.AddRange(x);
                list.AddRange(y);
                int[] z = list.ToArray();
            }
            Console.WriteLine("list.AddRange Test Time in ticks: {0}", (DateTime.Now - startTest).Ticks);

            startTest = DateTime.Now;
            for (int i = 0; i < itter; i++)
            {
                int[] z = Methods.Concat(x, y);
            }
            Console.WriteLine("Concat(x, y) Test Time in ticks: {0}", (DateTime.Now - startTest).Ticks);

            startTest = DateTime.Now;
            for (int i = 0; i < itter; i++)
            {
                int[] z = Methods.ConcatArrays(x, y);
            }
            Console.WriteLine("ConcatArrays Test Time in ticks: {0}", (DateTime.Now - startTest).Ticks);

            startTest = DateTime.Now;
            for (int i = 0; i < itter; i++)
            {
                int[] z = Methods.SSConcat(x, y);
            }
            Console.WriteLine("SSConcat Test Time in ticks: {0}", (DateTime.Now - startTest).Ticks);

            startTest = DateTime.Now;
            for (int k = 0; k < itter; k++)
            {
                int[] three = new int[x.Length + y.Length];

                int idx = 0;

                for (int i = 0; i < x.Length; i++)
                    three[idx++] = x[i];
                for (int j = 0; j < y.Length; j++)
                    three[idx++] = y[j];
            }
            Console.WriteLine("Roll your own Test Time in ticks: {0}", (DateTime.Now - startTest).Ticks);


            startTest = DateTime.Now;
            for (int i = 0; i < itter; i++)
            {
                int[] z = Methods.ConcatArraysLinq(x, y);
            }
            Console.WriteLine("ConcatArraysLinq Test Time in ticks: {0}", (DateTime.Now - startTest).Ticks);

            startTest = DateTime.Now;
            for (int i = 0; i < itter; i++)
            {
                int[] z = Methods.ConcatArraysLambda(x, y);
            }
            Console.WriteLine("ConcatArraysLambda Test Time in ticks: {0}", (DateTime.Now - startTest).Ticks);

            startTest = DateTime.Now;
            for (int i = 0; i < itter; i++)
            {
                List<int> targetList = new List<int>(x);
                targetList.Concat(y);
            }
            Console.WriteLine("targetList.Concat(y) Test Time in ticks: {0}", (DateTime.Now - startTest).Ticks);

            startTest = DateTime.Now;
            for (int i = 0; i < itter; i++)
            {
                int[] result = x.ToList().Concat(y.ToList()).ToArray();
            }
            Console.WriteLine("x.ToList().Concat(y.ToList()).ToArray() Test Time in ticks: {0}", (DateTime.Now - startTest).Ticks);
        }
    }
    static class Methods
    {
        public static T[] Concat<T>(this T[] x, T[] y)
        {
            if (x == null) throw new ArgumentNullException("x");
            if (y == null) throw new ArgumentNullException("y");
            int oldLen = x.Length;
            Array.Resize<T>(ref x, x.Length + y.Length);
            Array.Copy(y, 0, x, oldLen, y.Length);
            return x;
        }

        public static T[] ConcatArrays<T>(params T[][] list)
        {
            var result = new T[list.Sum(a => a.Length)];
            int offset = 0;
            for (int x = 0; x < list.Length; x++)
            {
                list[x].CopyTo(result, offset);
                offset += list[x].Length;
            }
            return result;
        }


        public static T[] SSConcat<T>(this T[] first, params T[][] arrays)
        {
            int length = first.Length;
            foreach (T[] array in arrays)
            {
                length += array.Length;
            }
            T[] result = new T[length];
            length = first.Length;
            Array.Copy(first, 0, result, 0, first.Length);
            foreach (T[] array in arrays)
            {
                Array.Copy(array, 0, result, length, array.Length);
                length += array.Length;
            }
            return result;
        }

        public static T[] ConcatArraysLinq<T>(params T[][] arrays)
        {
            return (from array in arrays
                    from arr in array
                    select arr).ToArray();
        }

        public static T[] ConcatArraysLambda<T>(params T[][] arrays)
        {
            return arrays.SelectMany(array => array.Select(arr => arr)).ToArray();
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

结果是:

在此输入图像描述

滚动你自己的胜利.

  • 我在发布模式下在 Visual Studio 2013 中运行了您的代码,发现如果测试的数组不像您的数组那么小(例如 1000 个元素),则 `CopyTo` 将是最快的,并且比 `Roll your own` 快 3 倍。 (2认同)

小智 6

public static T[] Concat<T>(this T[] first, params T[][] arrays)
{
    int length = first.Length;
    foreach (T[] array in arrays)
    {
        length += array.Length;
    }
    T[] result = new T[length];
    length = first.Length;
    Array.Copy(first, 0, result, 0, first.Length);
    foreach (T[] array in arrays)
    {
        Array.Copy(array, 0, result, length, array.Length);
        length += array.Length;
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)

  • 在StackOverflow,请不要只粘贴代码,还要解释您的方法.在这种特定情况下,您可能还需要解释您的迟到答案会给已经给出的答案(并接受) (2认同)
  • 你好Nyerguds.要回答您的问题,"this"关键字用于使函数成为扩展方法.有关扩展方法的详细信息,请查看此[MSDN文章](http://msdn.microsoft.com/en-us/library/vstudio/bb383977.aspx) (2认同)

小智 6

小心这个Concat方法.C#中的post Array Concatenation解释了:

var z = x.Concat(y).ToArray();
Run Code Online (Sandbox Code Playgroud)

对于大型阵列来说效率低下.这意味着该Concat方法仅适用于meduim大小的数组(最多10000个元素).

  • 包含超过10,000个元素的数组应该怎么做? (2认同)

小智 5

迟来的回答:-)。

public static class ArrayExtention
    {

        public static T[] Concatenate<T>(this T[] array1, T[] array2)
        {
            T[] result = new T[array1.Length + array2.Length];
            array1.CopyTo(result, 0);
            array2.CopyTo(result, array1.Length);
            return result;
        }

    }
Run Code Online (Sandbox Code Playgroud)


Dar*_*eal 5

这是我的回答:

int[] z = new List<string>()
    .Concat(a)
    .Concat(b)
    .Concat(c)
    .ToArray();
Run Code Online (Sandbox Code Playgroud)

此方法可用于初始化级别,例如定义静态数组的静态串联:

public static int[] a = new int [] { 1, 2, 3, 4, 5 };
public static int[] b = new int [] { 6, 7, 8 };
public static int[] c = new int [] { 9, 10 };

public static int[] z = new List<string>()
    .Concat(a)
    .Concat(b)
    .Concat(c)
    .ToArray();
Run Code Online (Sandbox Code Playgroud)

但是,它带有两个您需要考虑的警告:

  • Concat 方法在两个数组上创建一个迭代器:它不创建新数组,因此在使用的内存方面是有效的:但是,后续 ToArray  将否定这种优势,因为它实际上会创建一个新数组并占用内存新阵列。
  • 正如@Jodrell 所说,Concat对于大型数组来说效率很低:它应该只用于中型数组。

如果必须以性能为目标,则可以使用以下方法:

/// <summary>
/// Concatenates two or more arrays into a single one.
/// </summary>
public static T[] Concat<T>(params T[][] arrays)
{
    // return (from array in arrays from arr in array select arr).ToArray();

    var result = new T[arrays.Sum(a => a.Length)];
    int offset = 0;
    for (int x = 0; x < arrays.Length; x++)
    {
        arrays[x].CopyTo(result, offset);
        offset += arrays[x].Length;
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)

或者(对于单线球迷):

int[] z = (from arrays in new[] { a, b, c } from arr in arrays select arr).ToArray();
Run Code Online (Sandbox Code Playgroud)

虽然后一种方法要优雅得多,但前一种方法在性能上肯定更好。

有关更多信息,请参阅这篇文章在我的博客。


Ole*_*hov 5

从 C# 12 开始,您可以使用集合表达式扩展运算符 ..,例如:

int[] a = [1, 2, 3];
int[] b = [4, 5, 6];
int[] c = [..a, ..b];
Run Code Online (Sandbox Code Playgroud)

注意:虽然我目前不确定它的效率,但这绝对是最简洁、最简单的方法。此外,该功能是2023 年 11 月发布的.NET 8的一部分。