【问题标题】:MATLAB: Nested functions and structsMATLAB:嵌套函数和结构
【发布时间】:2013-08-13 18:20:16
【问题描述】:

总结:我想调用一个返回多个结构n次的函数。如何将结果附加到输出结构中的现有字段(即创建向量),而不是在每次迭代时创建包含标量的新字段?


示例:考虑一个函数sample_fct( x ) 1) 对x 执行一些操作并将结果保存在几个新变量中(示例代码中的ab ) 然后 2) 以ab 作为输入调用一些子函数calculate_one( x )calculate_two( x )。这些函数究竟是做什么的并不重要。然后将这些函数的输出收集到结构 AB 中。

function [A, B] = sample_fct( x )
    a = 1 * x;
    b = 2 * x;
    [A.one, A.two] = call_functions( a );
    [B.one, B.two] = call_functions( b );
    function [one, two] = call_functions( input )
        one = calculate_one( input );
        two = calculate_two( input );
        function one = calculate_one( input )
            one = input.^2;
        end
        function two = calculate_two( input )
            two = input.^3;
        end
    end
end

然后我想在我的脚本中使用不同的输入参数调用这个函数n

n = 3;
for i = 1:n
    [A(i), B(i)] = sample_fct( i );
end

当我这样做时,AB 成为 1*n 结构,每个字段再次包含字段 onetwo。所以在我的n = 3 示例中,我有3 个标量实例onetwo。我的示例代码的输出如下所示:

>> A
A = 
1x3 struct array with fields:
    one
    two
>> A.one
ans =
     1
ans =
     4
ans =
     9

我真正想要的是 AB 是具有 1*n 个向量 onetwo 的 1*2 结构,因此所需的输出应该如下所示:

>> A
A = 
    two: [1 8 27]
    one: [1 4 9]

如果没有 [one, two] 作为我的函数的输出变量并且没有分别为 A 和 B 调用我的函数,我该如何做到这一点?


我为什么要这样做:我想在时间序列上运行具有不同参数组合的预测模型,并计算 1 分钟、1 小时的一些拟合优度度量和其他统计数据, 1 天等交涉。在我的示例中,x 将是时间序列,n 上的循环是不同参数向量上的循环,ab 表示具有不同的采样时间和一个以及 two 一些我想要的统计信息聚集在结构 AB 中。我很确定有一种更复杂的方法可以做到这一点,但我无法理解它。

我知道使用向量/矩阵而不是结构很容易做到这一点,但我希望能够使用变量名而不是 A.hourly(:,19) 或类似的名称来调用我的输出,因为我在我的实际代码中计算许多统计数据,而不仅仅是两个。

【问题讨论】:

  • 你的问题很长,能不能在上面做一个简短的总结?
  • 我试过了,但我觉得我的问题有点太复杂,无法用几句话来概括。
  • 我刚刚阅读了摘要 :o --> 建议:将它们放入单元格数组中;好吧,如果这不是关于“如何将数据添加到我的矩阵”的问题...例如 a=[a newValues] 或 a(end+1)=newValues
  • 看我问题的最后一句话。 ;-) 我希望能够通过变量名访问我的结果,即 A.one 而不是 A{1} 因为在实际应用程序中,A 的字段比我的示例中的要多得多,我想避免混淆他们。
  • @FredS:你可能对这篇文章感兴趣:*.com/a/4169216/97160

标签: matlab struct nested


【解决方案1】:

编辑:根据 cmets 中提到的错误进行了更新。

您可以通过以下方式转换它们

A = struct('one', [A.one], 'two', [A.two]);

一般:

D = [fieldnames(A), cellfun(@(x) [A.(x)], fieldnames(A), 'Uni', false)].';
A = struct(D{:});

老答案

您可以通过

转换它们
A.one = [A.one];
A.two = [A.two];

一般

for theField = fieldnames(A)'
    F = theField{1};
    A.(F) = [A.(F)];
end

【讨论】:

  • 这是另一个非常有用的建议。谢谢。
  • 评估答案的第一行会引发错误:Incorrect number of right hand side elements in dot name assignment. Missing [] around left hand side is a likely cause.,尽管肯定有 []。我想这与原始 A.one 是一个 1*3 结构的 1*1 结构的事实有关,其中包含onetwo。除了使用不同的变量名之外,知道在这种情况下该怎么做吗?
  • @FredS 当您在没有测试的情况下编写答案时会发生这种情况。我用正确且经过测试的答案更新了它:-)
【解决方案2】:

另一种选择是让 sample_fct 将 A 和 B 作为附加参数,并在 sample_fct 内进行附加:

[A,B] = sample_fct(1)
for i=2:n
    [A,B] = sample_fct(i, A, B)
end

如果是 3-arguments-call,您必须更改 sample_fct 中的两个 call_functions 调用。这可以例如看起来像这样:

if nargin == 3
    [A.one(end+1), A.two(end+1)] = call_functions( a );
    [B.one(end+1), B.two(end+1)] = call_functions( b );
elseif nargin == 1
    [A.one, A.two] = call_functions( a );
    [B.one, B.two] = call_functions( b );
end

作为一般评论:在这种情况下,我看不出有任何使用嵌套函数的理由,因此我建议宁愿将它们作为普通子函数实现在同一个 m 文件中。

【讨论】:

  • 你说得对,在这种情况下不需要嵌套。您的第一个解决方案似乎对我有所不同。我需要为不同的输入评估一个和两个(这就是为什么我有单独的结构 A 和 B)。不过,您的第二个解决方案似乎是个好主意。我将尝试实现这一点。非常感谢。 /edit:哎呀,你的第一个解决方案已经消失了。 ;)