如何获取这些数组并使用它们来填充结构的字段?

Posted

技术标签:

【中文标题】如何获取这些数组并使用它们来填充结构的字段?【英文标题】:How can I take these arrays and use them to populate the fields of a structure? 【发布时间】:2020-12-02 02:07:17 【问题描述】:

我有几个向量,并想用它们来填充结构数组中的字段。向量只会有两种长度之一 - 它们的长度为 N 或长度为 1。例如,如果 N=3,我的向量可能如下所示:

a = [0 5 7]
b = [-2 6 8]
c = 6
d = [11 12 13]
e = 20

我希望结果是

my_structure(1).a = 0
my_structure(2).a = 5
my_structure(3).a = 7

my_structure(1).b = -2
my_structure(2).b = 6
my_structure(3).b = 8

my_structure(1).c = 6
my_structure(2).c = 6
my_structure(3).c = 6

my_structure(1).d = 11
my_structure(2).d = 12
my_structure(3).d = 13

my_structure(1).e = 20
my_structure(2).e = 20
my_structure(3).e = 20

您可以看到,对于仅初始长度为 1 的向量,结构数组的每个元素都应具有相同的值。

有没有一种简洁的方法来实现这一点而不必遍历每个元素?它应该是可扩展的,以便我可以添加更多向量 f,g,h,... 如果需要。

正如在 cmets 中查询的那样,我不能简单地使用 my_structure.a = [0 5 7] 等,因为我需要能够将 my_structure(i) 传递给另一个函数,这要求每个字段只包含一个值(而不是数组)。

【问题讨论】:

循环比这样的手写要简洁得多。在 MATLAB 中循环很慢是一个谬论,尤其是在最新的 JIT 更新之后。为什么循环不适合您的目的? 我不想这样手写 - 我只是写它来显示我希望每个查询的结果。 @Adriaan 我知道 Matlab 中有这些 arrayfun() 和 structfun() 函数,所以我怀疑有一种巧妙的方法可以使用它们来做到这一点。我一点也不担心循环变慢。 【参考方案1】:

更新答案

事实证明,您可以利用文档中的这一行:

如果任何值输入是非标量元胞数组,则s 与该元胞数组具有相同的维度。

所以

N = 3;          % Each var has 1 or N elements

a = [0 5 7];    
b = [-2 6 8];
c = 6;

% Create an anonymous function to make all vars the correct size CELL (1 or N)
pad = @(x) num2cell( repmat(x, 1, N/numel(x)) );
strct = struct( 'a', pad(a), 'b', pad(b), 'c', pad(c) );

这遵循与下面的原始答案类似的思维模式,但显然要简洁得多。


原答案

最简单的 详细的方法是从一个标量结构开始,然后将其转换为结构数组。所以...

N = 3;          % Each var has 1 or N elements

a = [0 5 7];    
b = [-2 6 8];
c = 6;

% Create an anonymous function to make all vars the correct size (1 or N)
pad = @(x) repmat(x, 1, N/numel(x));
% Create the scalar struct with padding
strctA = struct( 'a', pad(a), 'b', pad(b), 'c', pad(c) );

然后你可以有一个循环将它转换为一个结构数组,它与变量名没有联系,因此更容易维护:

f = fieldnames(strctA);  % Get the field names, i.e. the original variable names
strctB = struct([]);     % Create an output struct. The [] input makes it a struct array
for iFn = 1:numel(f)     % Loop over the fields
    for n = 1:N          % Loop over the array elements
        strctB(n).(fiFn) = strctA.(fiFn)(n); % Assign to new structure
    end
end

【讨论】:

感谢您的回答。这实现了我想要的,但比我预期的要麻烦一些。我认为使用 arrayfun() 或 structfun() 可以在没有循环的情况下完成,从而减少代码行,但您的解决方案甚至使用两个嵌套循环。也许“最简单”和“简洁”是两个不同的东西。 @teeeeee 请看我的编辑,原来我很接近但有一个更简单的答案。 太棒了,很好的发现——我学到了一些东西!似乎即使您在创建结构时省略了 c 中的 pad() 函数,它仍然可以工作。虽然我猜最好保留它。谢谢! @teeeeee 是的,标量将被复制/分发,但您必须将所有数组转换为单元格,否则它们也将被复制/分发。我编写了pad 函数,以便它在两种情况下都有效,您不必关心输入变量的大小。如果您不想要一般性,您可以将其用于相同的结果:struct( 'a', num2cell(a), 'b', num2cell(b), 'c', c )【参考方案2】:

Wolfie 的回答非常聪明,但您也可以使用更直接的解决方案,使用单个 for 循环:

N = 3;

a = [0 5 7]
b = [-2 6 8]
c = 6
d = [11 12 13]
e = 20

for i = 1:N
    my_structure(i).a = a(min(length(a), i))
    my_structure(i).b = b(min(length(b), i))
    my_structure(i).c = c(min(length(c), i))
    my_structure(i).d = d(min(length(d), i))
    my_structure(i).e = e(min(length(e), i))
end

这种方法的优点是您的代码更易于阅读。

【讨论】:

以上是关于如何获取这些数组并使用它们来填充结构的字段?的主要内容,如果未能解决你的问题,请参考以下文章

如何填充外部字段 ID 的 MongoDB 数组?

如何使用 SQL 表作为源填充 BIML 中的数组

如何创建脚本来自动填充字段?

我应该如何访问有关用于使用RxSwift和MVVM填充表格视图的数组的数据

MongoDB:使用子代数组填充父代vs通过父代ID搜索子代

以编程方式创建实体并将其添加到数组控制器