在.NET中合并两个数组

305

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

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

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

28个回答

556

在 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


3
我喜欢那个LINQ实现。我真的需要尽快开始使用LINQ... - GEOCHET
1
Rich,LINQ实现的最大优点不仅在于它简洁,而且它与2.0版本一样高效,因为它可以针对IEnumerable进行操作。 - Brad Wilson
这个答案提供了一种方法,并给出了一些基准测试结果:https://dev59.com/R3RC5IYBdhLWcg3wFNDX - Demir
1
这可能是最简单的方法,但对于大型数组来说效率不高,因为Concat是使用foreach循环+yield实现的(请参见参考源代码)。使用BlockCopy的解决方案将更快。 - tigrou
.Contat() 绝对是最简单的。根据我的经验,如果您想要删除重复项,只需在之后调用 .Distinct() 即可。 - Brian Tacker
1
小提示:如果您只想遍历组合结果,无需将其转换为数组。最后的操作会执行一个数组复制。如果您遍历 IEnumerable<int>,它就不必这样做。当然,将其设置为数组可能有很好的理由。 - Jonas

148

使用LINQ

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

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


167
注意:Union 操作将会移除重复项。 - Yogee
1
@Yogee,易于记忆,因为它就像在SQL中一样,并且命名法与集合理论相连。 - Chris W
1
我看到Simon已经提到了Union的问题和他建议的替代方法。不需要进一步讨论,因为Simon知道他在回答什么。 - Sudhakar Chavali

139

如果你能够操作其中一个数组,你可以在复制之前调整其大小:

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

在MSDN上了解更多可用的数组方法


1
.NET 4.0有什么消息吗? - Shimmy Weitzhandler
4
请注意,Array.Resize方法并不会实际调整数组大小,它会复制一份新的数组。这也是为什么第一个参数需要按引用传递的原因(这意味着你的第一个代码可能无法编译)。 - CodesInChaos
2
我建议你抛弃掉你的第一段代码。它没有任何优势,并且在我看来更难阅读。 - CodesInChaos
3
请注意,第二个Array.Copy代码示例的参数顺序是错误的。请改用Array.Copy(array1, newArray, 0);。 - marco birchler
你也可以这样做:List<byte> finalArray = new List<byte>(); finalArray.AddRange(array1); finalArray.AddRange(array2); ==>finalArray.toArray(); - Cédric Boivin

58
如果你不想去除重复项,那么可以尝试使用LINQ:
使用LINQ:
var arr1 = new[] { 1, 2, 3, 4, 5 };
var arr2 = new[] { 6, 7, 8, 9, 0 };
var arr = arr1.Concat(arr2).ToArray();

13
首先,确保你问自己这个问题:“我真的应该在这里使用数组吗”?
除非你正在构建一个速度至关重要的东西,否则像 List<int> 这样的类型化列表可能是更好的选择。我只在发送网络数据时使用字节数组。除此之外,我从不使用它们。

非常赞同。请注意,最佳实践是避免在公共API中暴露List<T>:http://blogs.msdn.com/b/kcwalina/archive/2005/09/26/474010.aspx - TrueWill

11

更简单的方法是使用LINQ

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

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


你没有直接使用数组,而是使用了列表! - Behzad Ebrahimi

7

这是我想到的方法,适用于变量数量的数组。

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 }

7

我认为你可以使用Array.Copy来实现这一目的。它接受源索引和目标索引,因此您应该能够将一个数组附加到另一个数组上。如果您需要比仅仅将一个数组附加到另一个数组更复杂的操作,请不要使用此工具。


6

虽然大家都已经发表了自己的意见,但我认为这种方法比“使用扩展方法”更易读:

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

然而,它只能在合并两个数组时使用。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接