如何在C#中为大型数组有效地分配公共初始值?

时间:2012-09-22 19:40:09

标签: c# arrays multidimensional-array initialization

如何有效地为大型数组分配公共初始值? 例如,如果我有一个100乘100乘100的整数数组,其中所有初始值都应为零。

在matlab中,我只想写:

array = zeros(100,100,100);

如果没有C#循环,我怎么能这样做?

5 个答案:

答案 0 :(得分:2)

仅仅是为了争论(我个人认为这不是一个好的编程风格)但它可以在一行中用C#完成,技术上没有循环但是使用LINQ

int[,,] cube = new int[A, B, C];
Enumerable.Range(0, A*B*C).Select(i => cube[i/(B*C), i%(B*C)/C, i%C] = 1).Count();

这里只需要Count()来枚举序列,忽略其结果。 这是为了实现MATLAB的ones()函数。 要实现零(),可以使用以下代码:

Array.Clear(cube, 0, A*B*C);

答案 1 :(得分:1)

public void SetAllValues(int[,,] data, int value) {
    for (int x = 0; x < data.GetLength(0); x++) {
        for (int y = 0; y < data.GetLength(1); y++) {
            for (int z = 0; z < data.GetLength(2); z++) {
                data[x, y, z] = value;
            }
        }
    }
}

答案 2 :(得分:1)

您可以像这样使用Enumerable.Repeat

int[] zeros1Dim = Enumerable.Repeat(0, 100).ToArray();
int[][] zeros2Dim = Enumerable.Repeat(zeros1Dim, 100).ToArray();
int[][][] array = Enumerable.Repeat(zeros2Dim, 100).ToArray();

答案 3 :(得分:0)

我不知道在C#中初始化数组的惯用的非循环方式,并且根据这里的答案,似乎没有其他人。不安全的内存复制可能需要更少的代码行,尽管它确实混淆了你正在做的事情的含义:它强调机制(将此值移动到此内存地址)超过语义(使整个多维数组等于相同的价值。)

鉴于此,我的建议是咬住子弹,使用循环,但然后以一种令人愉快的命名方法将其抽象出来

public static T[,,] FillArrayWithValue<T>(this T[,,] array, T value)
{
    // Loops go here
}

将其粘贴在某个静态实用程序类中,然后您的调用点变为:

int[,,] myArray = new int[4, 5, 6];
myArray.FillArrayWithValue(value);

答案 4 :(得分:-1)

在C编程领域,通常使用诸如memcpyCopyMemory之类的OS函数来有效地将内存从一个地方移动到另一个地方。这比使用循环要好得多,因为操作系统将使用专用硬件(DMA)来执行操作。

我不确定这对你的简单案例是否有用,但如果你愿意,可以从某些DLL导入这些函数。

[DllImport("kernel32.dll")]
static extern void CopyMemory(IntPtr destination, IntPtr source, uint length);

static void Main(string[] args)
{
    byte[] a = new byte[10]{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    byte[] b = new byte[10];

    IntPtr pa = Marshal.UnsafeAddrOfPinnedArrayElement(a, 0);
    IntPtr pb = Marshal.UnsafeAddrOfPinnedArrayElement(b, 0);

    CopyMemory(pb, pa, 10);
}

CopyMemory函数仅适用于连续的内存块,因此请注意您的调用方式。

重要编辑:

如果您查看下面的评论,您会注意到上面显示的代码片段远非“可用”,因为它可能会破坏您的应用程序内存,而您却不知道它。更好的方法是使用Buffer.BlockCopy method,正如codesparkle所建议的那样,它可能在内部做同样的事情,但是以安全的方式:

byte[] a = new byte[10]{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
byte[] b = new byte[10];
Buffer.BlockCopy(a, 0, b, 0, 10);