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

时间:2009-10-10 06:58:26

标签: 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 }));

-

现在我用

int[] z = x.Concat(y).ToArray();

是否有更简单或更有效的方法?

23 个答案:

答案 0 :(得分:296)

var z = new int[x.Length + y.Length];
x.CopyTo(z, 0);
y.CopyTo(z, x.Length);

答案 1 :(得分:74)

试试这个:

List<int> list = new List<int>();
list.AddRange(x);
list.AddRange(y);
int[] z = list.ToArray();

答案 2 :(得分:45)

你可以写一个扩展方法:

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

然后:

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

答案 3 :(得分:35)

我选择了一个更通用的解决方案,它允许连接任意一组相同类型的一维数组。 (我一次连接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;
    }

用法:

        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}

答案 4 :(得分:29)

就是这样:

using System.Linq;

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

// Concatenate array1 and array2.
var result1 = array1.Concat(array2);

答案 5 :(得分:10)

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

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

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

答案 6 :(得分: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();
        }
    }

}

结果是:

enter image description here

滚动你自己的胜利。

答案 7 :(得分: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;
}

答案 8 :(得分:5)

小心使用Concat方法。帖子 Array Concatenation in C# 解释了:

var z = x.Concat(y).ToArray();

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

答案 9 :(得分:4)

迟到的答案: - )。

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

    }

答案 10 :(得分:4)

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

我编写了一个简单的测试程序,用于“加热抖动”,在发布模式下编译并在我的机器上运行它而不需要附带调试器。

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

  

Concat花了3088ms

     

CopyTo花了1079ms

     

BlockCopy耗时603毫秒

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

  

Concat花了45945ms

     

CopyTo花了2230ms

     

BlockCopy需要1689毫秒

根据这些结果,我可以断言CopyToBlockCopy方法比Concat明显更有效,而且,如果绩效是目标,BlockCopy有价值CopyTo

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

答案 11 :(得分:2)

我使用LINQLambda表达式找到了一个优雅的单行解决方案,两者的工作方式相同(编译程序时LINQ转换为Lambda)。该解决方案适用于任何阵列类型和任意数量的阵列。

使用LINQ:

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

使用Lambda:

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

我提供了两个人的偏好。性能明智的@Sergey Shteyn's@deepee1's解决方案有点快,Lambda表达式最慢。所花费的时间取决于数组元素的类型,但除非有数百万次调用,否则这些方法之间没有显着差异。

答案 12 :(得分:2)

用于保存组合数组的RAM(和CPU)方面最有效的结构是实现IEnumerable(或者如果您希望从Array派生)并在内部链接到原始数组以读取值的特殊类。 AFAIK Concat就是这么做的。

在您的示例代码中,您可以省略.ToArray(),这样可以提高效率。

答案 13 :(得分:2)

你可以按照你提到的方式进行,或者如果你想真正手动操作它,你可以自己循环:

        string[] one = new string[] { "a", "b" };
        string[] two = new string[] { "c", "d" };
        string[] three;

        three = new string[one.Length + two.Length];

        int idx = 0;

        for (int i = 0; i < one.Length; i++)
            three[idx++] = one[i];
        for (int j = 0; j < two.Length; j++)
            three[idx++] = two[j];

答案 14 :(得分:1)

您需要记住的是,在使用LINQ时,您正在使用延迟执行。这里描述的其他方法都可以完美地工作,但它们会立即执行。此外,Concat()函数可能以您自己无法做到的方式进行优化(调用内部API,OS调用等)。 无论如何,除非你真的需要尝试和优化,否则你现在正在走向“万恶之源”;)

答案 15 :(得分:1)

尝试以下方法:

T[] r1 = new T[size1];
T[] r2 = new T[size2];

List<T> targetList = new List<T>(r1);
targetList.Concat(r2);
T[] targetArray = targetList.ToArray();

答案 16 :(得分:1)

很抱歉重振旧帖,但是这个怎么样:

static IEnumerable<T> Merge<T>(params T[][] arrays)
{
    var merged = arrays.SelectMany(arr => arr);

    foreach (var t in merged)
        yield return t;
}

然后在你的代码中:

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

var z=Merge(x, y);  // 'z' is IEnumerable<T>

var za=z.ToArray(); // 'za' is int[]

在您致电.ToArray().ToList().ToDictionary(...)之前,内存未分配,您可以自由“构建查询”并调用其中一个来执行或者只是通过使用foreach (var i in z){...}子句来完成所有这些操作,该子句一次从上面的yield return t;返回一个项目......

上述功能可以按如下方式扩展为:

static IEnumerable<T> Merge<T>(this T[] array1, T[] array2)
{
    var merged = array1.Concat(array2);

    foreach (var t in merged)
        yield return t;
}

因此在代码中,您可以执行以下操作:

int[] x1={1, 2, 3};
int[] x2={4, 5, 6};
int[] x3={7, 8};

var z=x1.Merge(x2).Merge(x3);   // 'z' is IEnumerable<T>

var za=z.ToArray(); // 'za' is int[]

其余的与以前一样。

对此的另一个改进是将T[]更改为IEnumerable<T>(因此params T[][]将变为params IEnumerable<T>[]),以使这些函数接受的不仅仅是数组。

希望这有帮助。

答案 17 :(得分:1)

这是我的答案:

int[] z = new List<string>()
    .Concat(a)
    .Concat(b)
    .Concat(c)
    .ToArray();

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

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

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

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

或者(对于单线粉丝):

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

尽管后一种方法要优雅得多,但前一种方法的性能肯定更好。

有关其他信息,请参阅我的博客上的this post

答案 18 :(得分:0)

对于较小的数组&lt; 10000个元素:

using System.Linq;

int firstArray = {5,4,2};
int secondArray = {3,2,1};

int[] result = firstArray.ToList().Concat(secondArray.ToList()).toArray();

答案 19 :(得分:0)

对于int [],你所做的一切对我来说都很好。 astander's回答也适用于List<int>

答案 20 :(得分:-1)

static class Extensions
{
    public static T[] Concat<T>(this T[] array1, params T[] array2) => ConcatArray(array1, array2);

    public static T[] ConcatArray<T>(params T[][] arrays)
    {
        int l, i;

        for (l = i = 0; i < arrays.Length; l += arrays[i].Length, i++);

        var a = new T[l];

        for (l = i = 0; i < arrays.Length; l += arrays[i].Length, i++)
            arrays[i].CopyTo(a, l);

        return a;
    }
}

我认为上述解决方案更为通用&amp;比我在这里看到的其他人轻。它更通用,因为它不限制只有两个数组的连接,而且更轻,因为它不使用LINQ也不使用List。

请注意,解决方案很简洁,增加的通用性不会增加显着的运行时开销。

答案 21 :(得分:-2)

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

int [] z = x.Union(y)。ToArray();

答案 22 :(得分:-3)

int[] scores = { 100, 90, 90, 80, 75, 60 };
int[] alice = { 50, 65, 77, 90, 102 };
int[] scoreBoard = new int[scores.Length + alice.Length];

int j = 0;
for (int i=0;i<(scores.Length+alice.Length);i++)  // to combine two arrays
{
    if(i<scores.Length)
    {
        scoreBoard[i] = scores[i];
    }
    else
    {
        scoreBoard[i] = alice[j];
        j = j + 1;

    }
}


for (int l = 0; l < (scores.Length + alice.Length); l++)
{
    Console.WriteLine(scoreBoard[l]);
}