簡體   English   中英

如何在 C# 中連接兩個 arrays?

[英]How do I concatenate two arrays in 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();

有沒有更簡單或更有效的方法?


小心使用Concat方法。 C# 中的 Array Concatenation 帖子解釋說:

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

對於大型 arrays 效率低下。這意味着Concat方法僅適用於中等大小的 arrays(最多 10000 個元素)。

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

試試這個:

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

你可以寫一個擴展方法:

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+。)

我的功能:

    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}

就是這個:

using System.Linq;

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

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

我知道 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();
        }
    }

}

結果是:

在此處輸入圖片說明

滾動你自己的勝利。

您可以在最后取消 ToArray() 調用。 在調用 Concat 之后,您是否需要將它作為數組?

調用 Concat 會在兩個數組上創建一個迭代器。 它不會創建新數組,因此您沒有為新數組使用更多內存。 當您調用 ToArray 時,您實際上確實創建了一個新數組並占用了新數組的內存。

因此,如果您只需要輕松地遍歷兩者,那么只需調用 Concat。

Array.CopyTo上使用Buffer.BlockCopy更有效(更快),

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 耗時 3088 毫秒

CopyTo 耗時 1079 毫秒

塊復制耗時 603 毫秒

如果我將測試數組更改為從 0 到 99 的兩個序列,那么我會得到與此類似的結果,

Concat 耗時 45945 毫秒

CopyTo 耗時 2230 毫秒

塊復制耗時 1689 毫秒

從這些結果中,我可以斷言CopyToBlockCopy方法明顯比Concat更有效,此外,如果以性能為目標, BlockCopyCopyTo更有價值。

需要注意的是,如果性能無關緊要,或者迭代次數很少,請選擇您認為最簡單的方法。 Buffer.BlockCopy確實提供了一些超出此問題范圍的類型轉換實用程序。

小心使用Concat方法。 C# 中的后數組連接解釋了:

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

對於大型陣列將效率低下。 這意味着Concat方法僅適用於中等大小的數組(最多 10000 個元素)。

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

遲到的答案:-)。

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

    }

這是我的回答:

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

雖然后一種方法要優雅得多,但前一種方法在性能上肯定更好。

有關更多信息,請參閱這篇文章在我的博客。

就 RAM(和 CPU)而言,保存組合數組的最有效結構是一個特殊的類,它實現 IEnumerable(或者,如果您希望甚至從 Array 派生)並在內部鏈接到原始數組以讀取值。 AFAIK Concat 就是這樣做的。

在您的示例代碼中,您可以省略 .ToArray() ,這會使其更有效率。

很抱歉恢復舊線程,但是如何:

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){...}子句foreach (var i in z){...}它們,該子句從yield return t;一次返回一個項目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>[] )以使這些函數接受的不僅僅是數組。

希望這可以幫助。

你可以按照你提到的方式來做,或者如果你想獲得真正的手冊,你可以滾動你自己的循環:

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

我找到了一個使用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@deepee1 的解決方案要快一些,Lambda 表達式是最慢的。 花費的時間取決於數組元素的類型,但除非有數百萬次調用,否則方法之間沒有顯着差異。

您需要記住的是,在使用 LINQ 時,您正在使用延遲執行。 此處描述的其他方法都可以完美運行,但它們會立即執行。 此外,Concat() 函數可能以您自己無法完成的方式進行了優化(調用內部 API、操作系統調用等)。 無論如何,除非您真的需要嘗試和優化,否則您目前正走在通往“萬惡之源”的道路上;)

請嘗試以下操作:

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

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

對於 int[] 你所做的對我來說看起來不錯。 旁觀者的回答也適用於List<int>

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

我認為上述解決方案比我在這里看到的其他解決方案更通用、更輕便。 它更通用,因為它不限制僅兩個數組的連接,並且更輕,因為它不使用 LINQ 或 List。

請注意,該解決方案是簡潔的,並且增加的通用性不會增加顯着的運行時開銷。

對於小於 10000 個元素的較小數組:

using System.Linq;

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

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

我認為一個列表將適用於此目的。

您可以創建這樣的列表。

List<int> Items = new List<int>();  

然后你可以很容易地使用 for each 循環來迭代任意數量的數組並將它們添加到列表中。

 foreach (int i in nameOfArray) { Items.Add(i); }

如果您使用列表,它將消除越界異常的問題。 列表可用於與數組相同的所有功能。 唯一有意義的區別是項目數量沒有硬性限制。

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

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

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM