【问题标题】:Matlab: associating an ID with a dataset (e.g. struct)?Matlab:将 ID 与数据集(例如结构)相关联?
【发布时间】:2019-09-04 19:45:24
【问题描述】:

我正在为 Matlab 中的高阶有限元模拟算法开发某个功能,我想知道什么是实现某个任务的好方法。我相信我面临着一个普遍的问题,但是在进行了一些挖掘之后,我并没有真正找到一个好的解决方案。

基本上,我有一长串 ID(对应于我的网格上的某些节点),其中每个 ID 都与小数据集相关联。然后,当我运行求解器时,我需要访问与这些节点关联的数据并更新数据(多次)。

例如,假设这是我的这些特定节点的列表:

nodelist = [3 27 38] %(so these are my node ID's) 

然后对于每个节点,我关联了以下数据集

a (scalar)
b (5x5 double matrix)
c (10x1 double vector)

(a total of 36 double values associated with each node ID)

实际上,我当然会有更长的节点 ID 列表和与每个节点关联的更大的数据集(但仍然只有双标量、矩阵和向量(没有字符、字符串等))。

方法 1

所以我设计的一种方法是将所有内容存储在 2D 双矩阵中,然后在需要时进行一些相对复杂的索引来访问我的数据。对于上面的示例,我的 2D 矩阵的大小将是

size(2Dmat) = [length(nodelist), 36]

假设我想访问节点 ID 27 的 b(3,3),我将访问 2Dmat(2,14)。

原则上,这是可行的,但是由于这种复杂的索引,代码不是很干净和可读(更不用说,当我更改数据集的设置方式时,我需要重新调整整个索引代码)。

方法 2

另一种方法是为节点列表中的每个节点使用某种结构:

a = 4.4;
b = rand(5,5);
c = rand(10,1);
s = struct('a',a,'b',b,'c',c)

然后我可以通过例如 s.b(3,3) 等访问数据。但我只是不知道如何将结构与节点 ID 相关联?

方法 3

我能想到的最后一件事是设置某种 SQL 数据库,但这似乎有点矫枉过正。此外,我需要我的代码尽可能快,因为我需要多次访问与这些选定节点关联的数据集中的这些字段,我想对数据库进行一些查询会减慢速度。

请注意,我最终会将代码从 Matlab 转换为 C/C++,因此我更愿意实现一些不太依赖于某些 Matlab 特定功能的东西。

那么,对于如何以干净的方式实现此功能有什么想法吗?我希望我的问题有意义,并提前感谢!

【问题讨论】:

  • 我至少会考虑使用cellscell arrays
  • 为什么不在 ID 结构中添加另一个字段?
  • 虽然现在我想起来了,也许一个以 ID 为键并以结构数组的索引为值的 Map 会更好,因为它可以更快地访问。
  • 您可以使用列表地图吗?关键是列表名称:mathworks.com/help/matlab/map-containers.html

标签: matlab data-structures struct finite-element-analysis


【解决方案1】:

方法 2 是最简洁的,并且很容易转换为 C++。对于每个节点,您都有一个结构 s,然后:

data(nodeID) = s;

就是所谓的结构数组。你索引为

data(id).b(3,3) = 0.0;

这假设 ID 是连续的,或者它们的值没有巨大的差距。但这总是可以确保的,如有必要,很容易重新编号节点 ID。


在 C++ 中,你会有一个结构向量:

struct Bla{
   double a;
   double b[3][3];
   double c[10];
};

std::vector<Bla> data(N);

或者在 C 中:

Bla* data = malloc(sizeof(Bla)*N);

(完成后不要忘记free(data))。

然后,在 C 或 C++ 中,您可以通过以下方式访问元素:

data[id].b[2][2] = 0.0;

翻译很明显,只是索引在 C++ 中从 0 开始,在 MATLAB 中从 1 开始。


请注意,此方法在 MATLAB 中比方法 1 具有更大的内存开销,但在 C 或 C++ 中则不然。

方法 3 是个坏主意,它只会减慢您的代码速度,而没有任何好处。

【讨论】:

  • 我假设 MATLAB 会为 ID [3 27 38] 的所有 38 个元素分配内存,但事实并非如此。
  • @beaker:它确实为它们分配了结构数组元素,但是如果你不给一个字段分配任何东西,这个字段就不会占用内存。无论如何,我假设节点 ID 在任何有意义的应用程序中都是连续的,如果不是,重新编号它们是微不足道的。
  • 非常感谢克里斯,这就像一个魅力,正是我所需要的。我可以问你,是否可以在 C 中做类似的事情,某种结构数组?到目前为止,我一直在使用 Matlab 和 C,因为我更熟悉 C 而不是 C++。 (我一直认为我必须在某个时候从 C 切换到 C++,但直到现在都设法避免这种情况......)
  • @FinnurPind:我用 C 等价的 std::vector 编辑了答案。 4 年前我从 C 转到 C++,再也不想回去了。 C++ 写起来更容易、更快捷。我不能推荐它。但是一定要学习 C++11,忘记之前的任何东西。 C++11 是一种与以前不同的语言。
  • 感谢@CrisLuengo 的编辑和您的见解。我显然应该从 C 到 C++ 的飞跃!
【解决方案2】:

我认为,给定一组不连续的节点 ID,最简洁的解决方案是使用 map container 的方法 2,其中您的节点 ID 是映射中的键(即索引)。这可以在 MATLAB 中使用 containers.Map 对象来实现,在 C++ 中使用 std::map 容器来实现。例如,以下是在 MATLAB 中创建节点映射并向其添加值的方法:

>> nodeMap = containers.Map('KeyType', 'double', 'ValueType', 'any');
>> nodelist = [3 27 38];
>> nodeMap(nodelist(1)) = struct('a', 4.4, 'b', rand(5, 5), 'c', rand(10, 1));
>> nodeMap(3)

ans = 

  struct with fields:

    a: 4.400000000000000
    b: [5×5 double]
    c: [10×1 double]

>> nodeMap(3).b(3,3)

ans =

   0.646313010111265

在 C++ 中,您需要为要存储在映射中的数据类型定义一个结构或类(例如 Node)。这是一个示例(... 表示传递给Node 构造函数的参数):

#include <map>

class Node {...};   // Define Node class
typedef std::map<int, Node> NodeMap;  // Using int for key type

int main()
{
  NodeMap map1;

  map1[3] = Node(...);  // Initialize and assign Node object
  map1.emplace(27, std::forward_as_tuple<...>);  // Create Node object in-place
}

【讨论】:

  • 如果 ID 必须是任意数字(在这种情况下甚至不需要是整数),这是一个很好的解决方案。但是,如果可以将 ID 定义为连续或几乎连续,则可以避免映射的开销(时间和空间)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-02-08
  • 1970-01-01
  • 2020-01-25
  • 2011-06-07
  • 2012-09-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多