如何在C#中快速将二维数组转换为一维数组?

2024-03-05

我有一个多维的double[,]数组,其大小为 [1,N](假设 N 已知)。将其转换为一维的最快方法是什么double[]长度为 N 的数组?

我是 C# 新手,我用它与 Matlab 函数交互。我使用的 Matlab 函数返回一个一维行向量。在 C# 中,它被视为object[,]我只能把它投射到double[,]。但是,我需要它的类型double[]作为另一个函数的输入。有没有一种快速方法可以将此二维双精度数组转换为具有相同元素和相同顺序的一维数组?

由于我正在开发实时应用程序,因此我需要尽可能快地进行转换。


最快的方法是直接内存复制方法之一,例如Buffer.BlockCopy https://learn.microsoft.com/en-us/dotnet/api/system.buffer.blockcopy?view=netframework-4.7.2, or Marshal.Copy https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.marshal.copy?view=netframework-4.7.2.

Example

var ary1 = new int[3,3];
ary1[0, 0] = 0;
ary1[0, 1] = 1;
ary1[0, 2] = 2;
ary1[1, 0] = 3;
ary1[1, 1] = 4;
ary1[1, 2] = 5;
ary1[2, 0] = 6;
ary1[2, 1] = 7;
ary1[2, 2] = 8;

var ary2 = new int[9];

Buffer.BlockCopy(ary1, 0, ary2, 0, 9 * sizeof(int));

Console.WriteLine(string.Join(",", ary2));

Output

0,1,2,3,4,5,6,7,8

你也可以使用memcpy,但是您将承担 PInvoke 的初始开销

[DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
public static extern IntPtr memcpy(IntPtr dest, IntPtr src, UIntPtr count);

基准测试

基准测试运行 100 次,每次运行后收集垃圾,并相互验证准确性,结果是从前 75% 的禁食运行中整理出来的,比例是多维数组的维度长度,即double[scale,scale]

┌──────────────────┬────────────────────────────────────────────┐
│        Test Mode │ Release (64Bit)                            │
│   Test Framework │ .NET Framework 4.7.1 (CLR 4.0.30319.42000) │
╞══════════════════╪════════════════════════════════════════════╡
│ Operating System │ Microsoft Windows 10 Pro                   │
│          Version │ 10.0.17763                                 │
├──────────────────┼────────────────────────────────────────────┤
│       CPU System │ Intel(R) Core(TM) i7-7700 CPU @ 3.60GHz    │
│  CPU Description │ Intel64 Family 6 Model 158 Stepping 9      │
├──────────────────┼──────────┬──────────────────┬──────────────┤
│  Cores (Threads) │ 4 (8)    │     Architecture │ x64          │
│      Clock Speed │ 3600 MHz │        Bus Speed │ 100 MHz      │
│          L2Cache │ 1 MB     │          L3Cache │ 8 MB         │
└──────────────────┴──────────┴──────────────────┴──────────────┘

字节数组的结果

┌── Standard input ──────────────────────────────────────────────────────────────────────┐
│ Value           │    Average │    Fastest │    Cycles │ Garbage │ Test │          Gain │
├── Scale 256 ────────────────────────────────────────────────────────────── 0.628 sec ──┤
│ MarshalCopy     │   6.450 µs │   4.300 µs │  26.698 K │ 0.000 B │ Pass │       24.21 % │
│ memcpy          │   7.992 µs │   4.700 µs │  32.758 K │ 0.000 B │ Pass │        6.09 % │
│ BlockCopy       │   8.511 µs │   4.600 µs │  37.053 K │ 0.000 B │ Base │        0.00 % │
│ ElemCopy Unsafe │  26.124 µs │  24.400 µs │  97.794 K │ 0.000 B │ Pass │     -206.96 % │
│ ElemCopy        │  75.426 µs │  72.300 µs │ 273.201 K │ 0.000 B │ Pass │     -786.27 % │
│ Linq            │   7.619 ms │   7.078 ms │  27.103 M │ 0.000 B │ Pass │  -89,429.16 % │
├── Scale 512 ────────────────────────────────────────────────────────────── 1.826 sec ──┤
│ MarshalCopy     │  17.939 µs │  17.300 µs │  68.142 K │ 0.000 B │ Pass │        1.33 % │
│ BlockCopy       │  18.182 µs │  17.300 µs │  69.770 K │ 0.000 B │ Base │        0.00 % │
│ memcpy          │  25.897 µs │  19.200 µs │  97.357 K │ 0.000 B │ Pass │      -42.44 % │
│ ElemCopy Unsafe │ 128.776 µs │ 102.400 µs │ 471.381 K │ 0.000 B │ Pass │     -608.28 % │
│ ElemCopy        │ 293.237 µs │ 285.400 µs │   1.055 M │ 0.000 B │ Pass │   -1,512.82 % │
│ Linq            │  31.057 ms │  29.750 ms │ 110.869 M │ 0.000 B │ Pass │ -170,714.99 % │
├── Scale 1,024 ──────────────────────────────────────────────────────────── 6.579 sec ──┤
│ memcpy          │ 268.747 µs │ 255.600 µs │ 972.409 K │ 0.000 B │ Pass │       12.28 % │
│ BlockCopy       │ 306.371 µs │ 291.500 µs │   1.104 M │ 0.000 B │ Base │        0.00 % │
│ MarshalCopy     │ 307.868 µs │ 293.100 µs │   1.111 M │ 0.000 B │ Pass │       -0.49 % │
│ ElemCopy Unsafe │ 583.684 µs │ 561.100 µs │   2.103 M │ 0.000 B │ Pass │      -90.52 % │
│ ElemCopy        │   1.325 ms │   1.305 ms │   4.768 M │ 0.000 B │ Pass │     -332.50 % │
│ Linq            │ 122.561 ms │ 120.700 ms │ 439.940 M │ 0.000 B │ Pass │  -39,904.01 % │
├── Scale 2,048 ─────────────────────────────────────────────────────────── 26.084 sec ──┤
│ memcpy          │   1.179 ms │   1.129 ms │   4.230 M │ 0.000 B │ Pass │       17.50 % │
│ MarshalCopy     │   1.397 ms │   1.346 ms │   5.029 M │ 0.000 B │ Pass │        2.25 % │
│ BlockCopy       │   1.429 ms │   1.360 ms │   5.135 M │ 0.000 B │ Base │        0.00 % │
│ ElemCopy Unsafe │   2.441 ms │   2.312 ms │   8.757 M │ 0.000 B │ Pass │      -70.88 % │
│ ElemCopy        │   5.466 ms │   5.264 ms │  19.587 M │ 0.000 B │ Pass │     -282.61 % │
│ Linq            │ 497.788 ms │ 489.885 ms │   1.786 B │ 0.000 B │ Pass │  -34,743.98 % │
├── Scale 4,096 ─────────────────────────────────────────────────────────── 42.833 sec ──┤
│ memcpy          │   5.218 ms │   4.889 ms │  18.633 M │ 0.000 B │ Pass │       15.45 % │
│ BlockCopy       │   6.172 ms │   5.887 ms │  22.141 M │ 0.000 B │ Base │        0.00 % │
│ MarshalCopy     │   6.255 ms │   5.871 ms │  22.350 M │ 0.000 B │ Pass │       -1.35 % │
│ ElemCopy Unsafe │   9.972 ms │   9.535 ms │  35.716 M │ 0.000 B │ Pass │      -61.57 % │
│ ElemCopy        │  22.149 ms │  21.741 ms │  79.508 M │ 0.000 B │ Pass │     -258.87 % │
│ Linq            │    1.969 s │    1.948 s │   7.067 B │ 0.000 B │ Pass │  -31,796.88 % │
└────────────────────────────────────────────────────────────────────────────────────────┘

双数组的结果

┌── Standard input ─────────────────────────────────────────────────────────────────────┐
│ Value           │    Average │    Fastest │    Cycles │ Garbage │ Test │         Gain │
├── Scale 256 ───────────────────────────────────────────────────────────── 0.688 sec ──┤
│ BlockCopy       │  35.116 µs │  32.000 µs │ 131.112 K │ 0.000 B │ Base │       0.00 % │
│ MarshalCopy     │  43.879 µs │  34.900 µs │ 162.031 K │ 0.000 B │ Pass │     -24.96 % │
│ ElemCopy Unsafe │  44.182 µs │  39.500 µs │ 162.891 K │ 0.000 B │ Pass │     -25.82 % │
│ memcpy          │  60.113 µs │  58.200 µs │ 219.950 K │ 0.000 B │ Pass │     -71.19 % │
│ ElemCopy        │  94.418 µs │  86.100 µs │ 356.173 K │ 0.000 B │ Pass │    -168.88 % │
│ Linq            │   7.402 ms │   7.123 ms │  26.638 M │ 0.000 B │ Pass │ -20,979.54 % │
├── Scale 512 ───────────────────────────────────────────────────────────── 2.237 sec ──┤
│ memcpy          │ 612.603 µs │ 552.000 µs │   2.199 M │ 0.000 B │ Pass │      10.20 % │
│ ElemCopy Unsafe │ 641.013 µs │ 586.200 µs │   2.312 M │ 0.000 B │ Pass │       6.03 % │
│ MarshalCopy     │ 675.192 µs │ 621.200 µs │   2.434 M │ 0.000 B │ Pass │       1.02 % │
│ BlockCopy       │ 682.161 µs │ 622.700 µs │   2.458 M │ 0.000 B │ Base │       0.00 % │
│ ElemCopy        │ 745.692 µs │ 708.800 µs │   2.687 M │ 0.000 B │ Pass │      -9.31 % │
│ Linq            │  33.579 ms │  31.039 ms │ 119.974 M │ 0.000 B │ Pass │  -4,822.46 % │
├── Scale 1,024 ─────────────────────────────────────────────────────────── 7.830 sec ──┤
│ memcpy          │   2.708 ms │   2.488 ms │   9.712 M │ 0.000 B │ Pass │      20.63 % │
│ ElemCopy Unsafe │   3.156 ms │   2.789 ms │  11.324 M │ 0.000 B │ Pass │       7.51 % │
│ MarshalCopy     │   3.208 ms │   2.979 ms │  11.508 M │ 0.000 B │ Pass │       5.97 % │
│ ElemCopy        │   3.342 ms │   3.091 ms │  12.021 M │ 0.000 B │ Pass │       2.05 % │
│ BlockCopy       │   3.412 ms │   2.959 ms │  12.234 M │ 0.000 B │ Base │       0.00 % │
│ Linq            │ 125.854 ms │ 122.872 ms │ 451.735 M │ 0.000 B │ Pass │  -3,588.76 % │
├── Scale 2,048 ────────────────────────────────────────────────────────── 29.876 sec ──┤
│ memcpy          │  10.989 ms │  10.288 ms │  39.509 M │ 0.000 B │ Pass │      15.14 % │
│ ElemCopy Unsafe │  12.075 ms │  11.418 ms │  43.436 M │ 0.000 B │ Pass │       6.76 % │
│ BlockCopy       │  12.950 ms │  12.462 ms │  46.578 M │ 0.000 B │ Base │       0.00 % │
│ MarshalCopy     │  13.032 ms │  12.427 ms │  46.876 M │ 0.000 B │ Pass │      -0.64 % │
│ ElemCopy        │  13.469 ms │  12.689 ms │  48.471 M │ 0.000 B │ Pass │      -4.01 % │
│ Linq            │ 502.897 ms │ 497.335 ms │   1.805 B │ 0.000 B │ Pass │  -3,783.35 % │
├── Scale 4,096 ────────────────────────────────────────────────────────── 58.669 sec ──┤
│ memcpy          │  45.901 ms │  44.148 ms │ 164.750 M │ 0.000 B │ Pass │      15.80 % │
│ ElemCopy Unsafe │  51.889 ms │  50.497 ms │ 186.137 M │ 0.000 B │ Pass │       4.82 % │
│ MarshalCopy     │  53.237 ms │  51.847 ms │ 191.248 M │ 0.000 B │ Pass │       2.34 % │
│ BlockCopy       │  54.514 ms │  52.417 ms │ 195.778 M │ 0.000 B │ Base │       0.00 % │
│ ElemCopy        │  56.551 ms │  54.674 ms │ 203.163 M │ 0.000 B │ Pass │      -3.74 % │
│ Linq            │    2.004 s │    1.976 s │   7.192 B │ 0.000 B │ Pass │  -3,575.84 % │
└───────────────────────────────────────────────────────────────────────────────────────┘

测试代码

[Test("BlockCopy", "", true)]
public double[] Test1(double[,] input, int scale)
{
   var width = input.GetLength(0);
   var height = input.GetLength(1);
   var size = width * height;
   var result = new double[size];
   Buffer.BlockCopy(input, 0, result, 0, size * sizeof(double));
   return result;
}

[Test("MarshalCopy", "", false)]
public unsafe double[] Test2(double[,] input, int scale)
{
   var width = input.GetLength(0);
   var height = input.GetLength(1);
   var size = width * height;
   var result = new double[size];
   fixed (double* pInput = input)
      Marshal.Copy((IntPtr)pInput, result, 0, size );
   return result;
}

[Test("ElemCopy", "", false)]
public double[] Test3(double[,] input, int scale)
{
   var width = input.GetLength(0);
   var height = input.GetLength(1);
   var size = width * height;

   var result = new double[size];
   for (var i = 0; i < width; i++)
      for (var j = 0; j < height; j++)
         result[i * height + j] = input[i,j];
   return result;
}
[Test("ElemCopy Unsafe", "", false)]
unsafe public double[] Test4(double[,] input, int scale)
{
   var width = input.GetLength(0);
   var height = input.GetLength(1);
   var size = width * height;

   var result = new double[size];
   fixed (double* pInput = input, pResult = result)
      for (var i = 0; i < width; i++)
         for (var j = 0; j < height; j++)
            *(pResult + i * height + j) = *(pInput + i * height + j);
   return result;
}
[Test("memcpy", "", false)]
unsafe public double[] Test5(double[,] input, int scale)
{
   var width = input.GetLength(0);
   var height = input.GetLength(1);
   var size = width * height;

   var result = new double[size];
   fixed (double* pInput = input, pResult = result)
      memcpy((IntPtr)pResult, (IntPtr)pInput, (UIntPtr)(size * sizeof(double)));
   return result;
}
[Test("Linq", "", false)]
unsafe public double[] Test6(double[,] input, int scale)
{
   return input.OfType<double>().ToArray();
}

Note : You should probably run these tests yourself on your own spec pcs, framework and such and should only be used as a guide

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在C#中快速将二维数组转换为一维数组? 的相关文章

  • c# - 显示小数点到小数点后 6 位 [重复]

    这个问题在这里已经有答案了 可能的重复 具有 N 个小数位的 Double ToString https stackoverflow com questions 3059759 double tostring with n number o
  • 为什么这个 oracle 批量插入不起作用?

    我正在尝试将一些数据批量插入到 oracle 数据库中 我按照文档中的示例进行操作 this DataBaseAccess new OracleConnection connString var dataAdapter new Oracle
  • WPF Dispatchertimer 延迟反应/冻结

    在我的 WPF 应用程序中 我使用 3 个不同的 DispatcherTimers 一种是用于显示当前时间 一种是每 5 秒运行一次数据库查询 第三个每 1 秒刷新一次自定义按钮的值 当我的程序运行时 有很多延迟 冻结 例如 时间开始正确计
  • 当我使用 SetWindowsHookEx WH_KEYBOARD_LL 交换按键时,为什么我的程序会陷入过多键盘输入事件的循环?

    I am trying to write a program for Windows system that swaps the A and B keys i e when I press the A key B gets typed an
  • 它们是“相同的”吗?代码大战

    这是完整的问题描述 给定两个数组 a 和 b 编写一个函数 comp a b Clojure 中的 compSame a b 来检查这两个数组是否具有 相同 元素以及相同的重数 这里 相同 意味着 b 中的元素是 a 平方中的元素 无论顺序
  • & 运算符的含义是什么?

    在下面的代码中 Expression
  • 试图使用加密来混淆我的项目打破了它

    我试图尝试不同的混淆选项 为了做到这一点 我首先尝试了加密货币 以下是我遵循的步骤 打开加密向导并选择一些选项 选择我的解决方案文件 完成向导后 我看到有些 Dll 被很好地混淆了 但我的项目现在无法构建 我注意到的两件事是 我的文件夹中有
  • EF Core 一对多关系列表返回 null

    我正在尝试学习如何在 EF Core 中正确利用 DbContext 我有一个团队课程 public class Team public int ID get set public string Name get set public bo
  • ASP.NET中如何访问除wwwroot以外的位置

    我可以使用访问服务器的物理位置Server MapPath 这给了我内部的物理路径wwwroot文件夹 我想将一些数据保存到同一服务器的另一个驱动器中D 驾驶 我想我无法获取以下位置的物理位置D 驾驶使用Server MapPath因为它位
  • 我可以在 C++ 中重写非虚函数吗

    我想知道我可以重写 C 中的非虚函数吗 因为我在使用 C 时发现了这个问题override关键字我的代码如下 class A public void say cout lt lt From A n class B public A publ
  • 三种 System.Drawing 方法表现出缓慢的绘制或闪烁:解决方案?或其他选择?

    我正在通过 System Drawing 进行一些绘图 但遇到了一些问题 我将数据保存在队列中 并将该数据绘制 绘制 到三个图片框中 此方法填充图片框 然后滚动图形 所以不要在以前的绘图上绘制 并且逐渐看起来更混乱 我找到了两种绘制图表的解
  • 如何使用 ProtoGen 从 proto 文件生成结构

    我们一直在使用 protobuf net ProtoGen 从 proto 文件生成 C cs 文件 我们希望代替类来生成结构 例如 DataContract public struct Entity1 ProtoMember 1 publ
  • Nuget - 对象引用未设置为对象的实例

    我在 vs 2015 中遇到了 nuget 包管理器的问题 像Unity这样的一些包已经安装没有问题了 某些软件包 例如 EF 在安装时出现问题 像 Automapper 这样的一些软件包也有同样的问题 但是当我安装这个软件包的另一个版本时
  • 生成范围 [min,max] 内的随机数 [重复]

    这个问题在这里已经有答案了 我正在使用 C 生成范围 min max 内的整数随机数 我在用 int random int int min int max return min rand max min 但我认为上面的代码适用于范围 min
  • 如何在asp.net core 6中注入IConfiguration

    web api 应用程序中不再有 Startup cs 我们以前可以注入IConfiguration进入那个Startup class public class Startup public Startup IConfiguration c
  • 使用非字符串作为字符串(而不是自动使用 ToString)时如何显示错误?

    建议的重复确实是一个类似的问题 然而 答案只涵盖一种选择 禁用 ToString 本身 还有其他可能的解决方案 例如让 Visual Studio 警告我 或者不调用 ToString 仔细阅读那里的答案 他认为is调用 只是解释说没有办法
  • C++ 联合数组和变量?

    在C 中没有办法做这样的事情吗 union Scalar x y Scalar v 2 Where x v 0 and y v 1 既然您使用的是 C 而不是 C 并且它们具有相同的类型 为什么不直接将 x 设为对 v 0 的引用 将 y
  • 如何创建和使用类箭头运算符? [复制]

    这个问题在这里已经有答案了 因此 在到处研究之后 我似乎找不到如何创建类箭头运算符 即 class Someclass operator gt 我只需要知道如何使用它并正确使用它 它的输入是什么 它返回什么 我如何正确地声明 原型化它 运算
  • NSCF 数组越界?

    我有一个相当简单的应用程序 使用 Core Data 和几个数组控制器 在 IB 中 除了 xcdatamodel 文件之外 没有它们的代码文件 当我运行应用程序时 我在日志中收到以下错误 应用程序仍然运行 但在转到 文件 gt 新文档 之
  • char[length]初始化并处理

    我定义了一个字符数组 char d 6 如果我在以下方面有误 请纠正我 此时没有为变量分配内存d 现在我要初始化它 d aaaaa 这种初始化之后 就不需要释放内存了 它将自动完成 我怎么知道是否char 被初始化了吗 我正在寻找类似的模式

随机推荐