【问题标题】:Itererating over class properties in Matlab在 Matlab 中迭代类属性
【发布时间】:2016-06-30 23:14:09
【问题描述】:

我根据来自数据的变量列表创建了一个类。我做了一个函数,它将所有数据放在这个类的一个对象中。

随着变量列表的增加,我不得不不断调整类和加载函数。我正在尝试找到一种方法,使我的加载功能对类中的更改具有鲁棒性。

类文件代码:

classdef CoolClass
    properties
        prop_a
        prop_b
        prop_c
    end
end

我编写的将这些数据加载到对象中的函数:

function [ object_name ] = loadCoolClass (data_file_name)

    load(data_file_name) 
    % this loads the variabels: 
    % prop_a = 1, prop_b = 2, prop_c = 3, prop_d = 4

    object_name = CoolClass;

    object_name.prop_a = prop_a;
    object_name.prop_b = prop_b;
    object_name.prop_c = prop_c;
end

现在我想要的是,如果我将变量 prop_d 添加到 classdef 文件,它也会立即将其加载到加载文件中。像这样:

function [ object_name ] = loadCoolClass (data_file_name)

    load(data_file_name) 
    % this loads the variabels: 
    % prop_a = 1, prop_b = 2, prop_c = 3, prop_d = 4

    object_name = CoolClass
    cool_properties = properties(CoolClass)

    for i = 1:size(cool_properties,2)
        object_name.cool_property(i) = cool_property(i)
    end
end

现在我知道上面的循环不是有效代码,但我的意思是:检查每个属性是否存在具有该名称的变量并将其放入对象中。

matlab 中有没有办法使用保存字符串的变量作为输入来加载以字符串内容命名的变量的值?

这是否可以在“=”符号之前命名内容 这是否可以在“=”符号后引用变量

【问题讨论】:

    标签: matlab class oop object class-properties


    【解决方案1】:

    我不知道您尝试做的事情是否有意义,但我认为您正在寻找函数 eval: object_name.cool_property(i) = eval(cool_property(i))

    【讨论】:

    • 哦,这确实是我寻找的解决方案的一部分。但它确实只解决了'='之后的问题。它仍然在 object_name.cool_property(i) = ... 上给出错误。动态结构引用的参数必须评估为有效的字段名称。
    • 你的提示给了我解决问题的重要方法:解决方案是:object_name.(char(cool_property(i))) = eval(cool_property(i))
    • Noooo 请不要使用 eval,也请不要建议使用 eval。
    • 嘿@rayryeng!请不要对我的回答投反对票。我同意 eval 是丑陋的。但这正是 Paco 一直在寻找的,我认为这是最接近他的问题的答案。正如我所写的,我不确定它是否有意义。也许你有更好的答案?
    • @ThierryDalon Suever 已经有了更好的答案。如果有没有 eval 的解决方案,则不应使用 eval。如果用户询问并且您想用 eval 回答,那么不要。那么如果你真的想用 eval 来回答,那就做,但是要明确 eval 既危险又低效。仅仅将其作为“越狱免费卡”而放弃是无益的,并准备好接受其他用户的批评。对于它的价值,我没有否决你的答案。
    【解决方案2】:

    根据我的经验,最简单的方法是让你的类成为hgsetget 的子类。这使您能够像使用图形对象一样使用set(obj, 'Key', value)get(obj, 'Key', value)

    cls = CoolClass();
    set(cls, 'prop_a', 1)
    

    第二步是specify an output to load(而不仅仅是将数据转储到您的工作区),这将为您提供一个结构,其中包含文件中每个变量的字段。建议何时从文件中加载以保持工作空间整洁。

    现在,将hgsetget 子类化的真正好处是you can also pass a struct of property/valuessetget

    示例

    classdef CoolClass < hgsetget
        properties
            prop_a
            prop_b
        end
    end
    

    现在,如果您有一个包含 prop_aprop_b 值的文件 data.mat,那么您可以执行此操作。

    cls = CoolClass();
    data = load('data.mat')
    
        prop_a: 1
        prop_b: 2
    
    set(cls, data)
    

    如果您在 data.mat 中有变量不是您的类的属性,您可以轻松过滤掉这些变量并仍然使用 set

    toremove = setdiff(fieldnames(data), props);
    set(cls, rmfield(data, toremove);
    

    更好的例子

    我个人会做的是编写一个构造函数,它接受与set 相同的输入(即结构或参数/值对),然后在构造函数内部,将它们直接传递给set。此外,您可以为该类实现loadobj 方法,该方法本质上是一个接受结构作为输入的静态方法。您可以在该方法中执行所有验证以删除不需要的字段。

    classdef CoolClass < hgsetget
        properties
            prop_a
            prop_b
        end
    
        methods
            function self = CoolClass(varargin)
                set(self, varargin{:});
            end
        end
    
        methods (Static)
            function obj = loadobj(S)
                obj = CoolClass();
    
                % Remove any invalid fields
                toremove = setdiff(fieldnames(S), properties(cls));
                set(obj, rmfield(S, toremmove))
            end
        end
    end
    

    现在您可以使用与以前不同的两种其他方式来使用此类。

    cls = CoolClass(load('data.mat'));
    cls = CoolClass.loadobj(load('data.mat'));
    

    【讨论】:

    • 哇,这超级有用。我正在处理一个包含大约 30 个变量的项目,我们不断地添加和删除它们。您的解决方案确实可以帮助我们减少更改变量时的开销。
    • @PacoHamers 很高兴为您提供帮助。我已经更新了一个更完整的示例,该示例演示了如何修改构造函数以接受这些结构作为输入。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-18
    • 1970-01-01
    • 1970-01-01
    • 2016-06-15
    • 2018-12-23
    • 2011-11-09
    相关资源
    最近更新 更多