C# 将三维数组转换为二维数组

C# 将三维数组转换为二维数组,c#,arrays,flatten,C#,Arrays,Flatten,我有一个字节数组: byte[,,] somedata = new byte[100,150,3]; ~somedata is now populated by an external input. 我只想使用以下内容中的值: byte[,] useThisDataOnly = new byte[100,150]; 目前,我使用的是: foreach (int x=0,x< 100; x++) { foreach (int y=0,y< 150; y++) {

我有一个字节数组:

byte[,,] somedata = new byte[100,150,3];
~somedata is now populated by an external input.
我只想使用以下内容中的值:

byte[,] useThisDataOnly = new byte[100,150];
目前,我使用的是:

foreach (int x=0,x< 100; x++)
{
    foreach (int y=0,y< 150; y++)
    {
       useThisDataOnly [x,y] = somedata[x,y,0];
    }
}
foreach(intx=0,x<100;x++)
{
foreach(int y=0,y<150;y++)
{
useThisDataOnly[x,y]=somedata[x,y,0];
}
}
有没有更快的方法

此外,我还打算将此useThisDataOnly展平(因为我听说使用它操作起来更快)


有什么建议吗?

优化这一点的困难在于,要省略的字节位于“移动最快”的索引中

我的意思是:如果将连续的数字分配给每个数组元素,如下所示:

byte[,,] source = new byte[100, 150, 3];

for (int i = 0, n = 0; i < 100; ++i)
    for (int j = 0; j < 150; ++j)
        for (int k = 0; k < 3; ++k, ++n)
            source[i, j, k] = unchecked ((byte)n);
因此,您可以看到,为了将输入转换为输出,您需要每三个字节进行一次转换,不幸的是,没有快速的方法可以做到这一点

但是,如果您能够要求创建数组时先省略索引:

byte[,,] source = new byte[3, 100, 150];
然后您就可以使用
Buffer.BlockCopy()

我想这不是一个选项-如果不是,那么手工编码的循环可能是最快的,您可以不用求助于不安全的代码来完成它

不安全代码

下面是使用不安全代码和指针的方法。这甚至可能不会使它更快,因此在选择这样做之前,您需要(a)确保使用简单的方法速度太慢,并且(b)使用
Stopwatch
仔细计时发布版本,以确保使用不安全的代码是值得的

还要注意使用不安全代码的缺点!不安全的代码需要提升权限,并可能导致程序因低级C++风格的野生指针错误而崩溃

using System;
using System.Diagnostics;

namespace Demo
{
    internal static class Program
    {
        static void Main()
        {
            byte[,,] source = new byte[100, 150, 3];

            for (int i = 0, n = 0; i < 100; ++i)
                for (int j = 0; j < 150; ++j)
                    for (int k = 0; k < 3; ++k, ++n)
                        source[i, j, k] = unchecked ((byte)n);

            byte[,] dest1 = new byte[100, 150];
            byte[,] dest2 = new byte[100, 150];

            for (int i = 0; i < 100; ++i)
                for (int j = 0; j < 150; ++j)
                    dest1[i, j] = source[i, j, 0];

            unsafe
            {
                fixed (byte* sp = source)
                fixed (byte* dp = dest2)
                {
                    byte* q = dp;
                    byte* p = sp;

                    for (int i = 0; i < 100*150; ++i)
                    {
                        *q++ = *p;
                        p += 3;
                    }
                }
            }

            for (int i = 0; i < 100; ++i)
                for (int j = 0; j < 150; ++j)
                    Trace.Assert(dest1[i, j] == dest2[i, j], "Arrays should be identical");
        }
    }
}
使用系统;
使用系统诊断;
名称空间演示
{
内部静态类程序
{
静态void Main()
{
字节[,]源=新字节[1001503];
对于(int i=0,n=0;i<100;++i)
对于(int j=0;j<150;++j)
对于(int k=0;k<3;++k,++n)
源[i,j,k]=未检查((字节)n);
字节[,]dest1=新字节[100150];
字节[,]dest2=新字节[100150];
对于(int i=0;i<100;++i)
对于(int j=0;j<150;++j)
dest1[i,j]=源[i,j,0];
不安全的
{
已修复(字节*sp=源)
固定(字节*dp=dest2)
{
字节*q=dp;
字节*p=sp;
对于(int i=0;i<100*150;++i)
{
*q++=*p;
p+=3;
}
}
}
对于(int i=0;i<100;++i)
对于(int j=0;j<150;++j)
Assert(dest1[i,j]==dest2[i,j],“数组应该相同”);
}
}
}

我个人认为使用简单、安全的循环不会太慢,但现在至少你有一些代码可以尝试。

你说的更快、更高性能是什么意思?在这些数组大小下,除非你经常这样做,否则没有关系。@thumbmunkeys嗨,谢谢你的时间和评论,是的,我被要求每秒接收许多这样的数组(唉,我无法控制)。我想我在这里问了两个问题。我主要关注的是在低内存使用率下,在不使用foreach的情况下,尽快将3dim转换为2dim:)hi@AlexFarber一个很好的链接(+1来自我),但示例显示[,]到[]。我理想的目标是[,]到[]?我建议与其预先优化内存,不如先尝试快速和脏循环,然后测量性能。然后你就会知道这是否是个问题。如果是的话,看看并行性;请参阅Task Parallel library您可以始终拥有一个C++/CLI库(允许您执行真正的非托管代码并将其反馈给普通的C#apps)来完成密集型方面的工作。但我的猜测是,如果你能把你的工作分成4/8个部分,并有并行的任务,你就会得到你需要的性能。嗨,谢谢你这么全面。我理解你的意思,这对我来说很有意义。不幸的是,我无法控制输入。但是我对不安全的代码语句很好奇。您是否暗示存在使用不安全技术的方法,如果是,您是否建议不要使用这种方法?谢谢您的时间。@AndrewSimpson是的,您可以使用不安全的代码和指针,但这意味着您的程序集(或任何使用它的程序集)必须标记为“不安全”,这可能会带来安全隐患。尽管如此,我还是会发布示例代码,以便您可以看到。这可能会使它快一点,但很可能不会!你真好。非常感谢您花了这么多时间!嗨,非常感谢你。我会按照你的建议进行测试。谢谢
byte[,,] source = new byte[3, 100, 150];
using System;
using System.Diagnostics;

namespace Demo
{
    internal static class Program
    {
        static void Main()
        {
            byte[,,] source = new byte[100, 150, 3];

            for (int i = 0, n = 0; i < 100; ++i)
                for (int j = 0; j < 150; ++j)
                    for (int k = 0; k < 3; ++k, ++n)
                        source[i, j, k] = unchecked ((byte)n);

            byte[,] dest1 = new byte[100, 150];
            byte[,] dest2 = new byte[100, 150];

            for (int i = 0; i < 100; ++i)
                for (int j = 0; j < 150; ++j)
                    dest1[i, j] = source[i, j, 0];

            unsafe
            {
                fixed (byte* sp = source)
                fixed (byte* dp = dest2)
                {
                    byte* q = dp;
                    byte* p = sp;

                    for (int i = 0; i < 100*150; ++i)
                    {
                        *q++ = *p;
                        p += 3;
                    }
                }
            }

            for (int i = 0; i < 100; ++i)
                for (int j = 0; j < 150; ++j)
                    Trace.Assert(dest1[i, j] == dest2[i, j], "Arrays should be identical");
        }
    }
}