Matlab/Octave中结构体内容和字段名称的格式化打印

3
我需要在命令窗口打印一个结构体的内容,其中包括对应的字段名和每个结构元素周围的一些文本。
例如:This something [fieldname(i)] has the value of [struct.fieldname(i) value] something. 经过半天的苦恼,我得到了一个表达式(不起作用)和一个循环(可以工作)。
问题 - 有没有一种方法可以不使用循环来实现这个目标?
代码:
box.apples = 25
box.cherries = 0.5
box.iron = 0.085

% Loop method (works)
for i = (1:length(struct2cell(box))) ;
    printf('There are %.3f kg of %s in the box \n', struct2cell(box){i}, fieldnames(box){i})
end
% Single expression method (doesn't work)
printf('There are %.3f kg of %s in the box \n', struct2cell(box){:}, fieldnames(box){:})

循环返回的输出正是我想要的:
There are 25.000 kg of apples in the box 
There are 0.500 kg of cherries in the box
There are 0.085 kg of iron in the box

只有printf表达式返回这个奇怪的输出:

There are 25.000 kg of  in the box
There are 0.085 kg of apples in the box
There are 99.000 kg of herries in the box
There are 105.000 kg of ron in the box

欢迎提出建议


1
你确定在开始之前清空了你的框吗?在你发布的代码中没有任何地方会输入99和105。 - Flynn
1
您提供的代码出现了错误,即使是循环版本也是如此?您使用的MATLAB版本是什么? - Wolfie
1
@Flynn 我可以验证那个105的神奇出现,我也得到了一些其他意外的值。我预计这个105来自于iron中缺失的i,因为char(105)='i',同样地,char(99)='c'来自于'cherries' - Wolfie
@Wolfie 感谢您提供有关字符转换的提示,我没有注意到!我正在使用Octave 4.2.1。 - Codethis
3个回答

4
在GNU Octave中(Matlab请参见Wolfie的回答):
box.apples = 25
box.cherries = 0.5
box.iron = 0.085
printf('There are %.3f kg of %s in the box \n',
       horzcat(struct2cell(box),fieldnames(box))'{:});

而“105.000”出现的原因是您将“iron”作为%f输入。请查看以下内容(这应该可以解释您奇怪的结果):

printf ('%f', 'iron')

(struct2cell(box),fieldnames(box))'{:} 这段代码在 Matlab 中肯定行不通,但是看起来 OP 在使用 Octave,这是一个很好的解决方案。 - Leander Moesinger
在MATLAB中,printf也不起作用,请参阅我的答案摘要。 - Wolfie
@Andy 非常感谢,我早该问了! 我不确定为什么要将铁提供给%f,特别是为什么只有第一个字符..我需要仔细思考你的答案。哦,忘了提一下,我用的是Octave 4.2.1。 - Codethis

2

这种方法适用于MATLAB和Octave:

c = vertcat(struct2cell(box).',fieldnames(box).');
fprintf('There are %.3f kg of %s in the box \n', c{:});

在MATLAB中,您必须在语句中使用括号()来结束它们。因此,您不能这样做:
c = struct2cell(box){:};

并且必须执行

c = struct2cell(box);
c = c{:};

MATLAB还要求您使用fprintf而不是printf。 您可以在这里看到一些语言差异。



2

我想在以上答案中提供我的意见。

"不使用循环"并不一定总是更快。特别是现在有了matlab的JIT编译器,它可以加速循环。所以不要仅仅为了让代码变得简洁而避免循环,这样做可能会导致代码难以阅读。此外,一行代码并不一定等于向量化。如果对速度有疑问,请进行简单的测试用例基准测试。

此外,循环通常更易读,因此,除非避免循环可以大幅提高速度,否则为了微小的优化而牺牲可读性通常是不值得的。

话虽如此,以下是我将如何编写该循环的方式:

  for CellStr = fieldnames(box).'
    Name = CellStr{1};
    fprintf('There are %.3f kg of %s in the box\n', box.(Name), Name)
  end

如果您正在使用Octave,Octave提供了以下精美的语法:

for [Val, Field] = box
  fprintf('There are %.3f kg of %s in the box\n', Val, Field)
end

我的机器上运行的一些基准测试结果 (使用octave,不开启JIT编译,在10000次迭代后的用时):

one-liner in answers above = 0.61343 seconds
top loop shown above       = 0.92640 seconds
bottom loop shown above    = 0.41643 seconds <-- wins
loop shown in the question = 1.6744  seconds

因此,在这种特殊情况下,其中一种for循环方法实际上比单行方法更


还请注意,box是Matlab / Octave中的一个函数名称,使用遮蔽内置函数的变量名称通常是一个不好的想法。 通常可以通过为变量使用大写字母或仅在调用变量之前查找该名称的函数来解决此问题。


1
绝对正确,for [Val, Field] = box 语法真的很可爱 +1。 - Andy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接